style.c 15.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * RichEdit style management functions
 *
 * Copyright 2004 by Krzysztof Foltman
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 20 21 22 23
 */

#include "editor.h"

WINE_DEFAULT_DEBUG_CHANNEL(richedit);
24
WINE_DECLARE_DEBUG_CHANNEL(richedit_style);
25 26 27

static int all_refs = 0;

28 29 30 31 32 33 34 35
/* the following routines assume that:
 * - char2[AW] extends char[AW] by adding fields at the end of the charA form)
 * - szFaceName is the last field of char[AW] form, and wWeight the first of 2[AW]
 * - the difference between A and W form is the szFaceName as Ansi vs Unicode string
 * - because of alignment, offset of wWeight field in 2[AW] structure *IS NOT*
 *   sizeof(char[AW])
 */

36 37 38 39 40
CHARFORMAT2W *ME_ToCF2W(CHARFORMAT2W *to, CHARFORMAT2W *from)
{
  if (from->cbSize == sizeof(CHARFORMATA))
  {
    CHARFORMATA *f = (CHARFORMATA *)from;
41
    CopyMemory(to, f, FIELD_OFFSET(CHARFORMATA, szFaceName));
42 43 44 45 46 47 48 49 50 51 52
    to->cbSize = sizeof(CHARFORMAT2W);
    if (f->dwMask & CFM_FACE) {
      MultiByteToWideChar(0, 0, f->szFaceName, -1, to->szFaceName, sizeof(to->szFaceName)/sizeof(WCHAR));
    }
    return to;
  }
  if (from->cbSize == sizeof(CHARFORMATW))
  {
    CHARFORMATW *f = (CHARFORMATW *)from;
    CopyMemory(to, f, sizeof(*f));
    /* theoretically, we don't need to zero the remaining memory */
53
    ZeroMemory(&to->wWeight, sizeof(CHARFORMAT2W)-FIELD_OFFSET(CHARFORMAT2W, wWeight));
54 55 56 57 58
    to->cbSize = sizeof(CHARFORMAT2W);
    return to;
  }
  if (from->cbSize == sizeof(CHARFORMAT2A))
  {
59
    CHARFORMAT2A *f = (CHARFORMAT2A *)from;
60
    /* copy the A structure without face name */
61
    CopyMemory(to, f, FIELD_OFFSET(CHARFORMATA, szFaceName));
62 63
    /* convert face name */
    if (f->dwMask & CFM_FACE)
64
      MultiByteToWideChar(0, 0, f->szFaceName, -1, to->szFaceName, sizeof(to->szFaceName)/sizeof(WCHAR));
65
    /* copy the rest of the 2A structure to 2W */
66
    CopyMemory(&to->wWeight, &f->wWeight, sizeof(CHARFORMAT2A)-FIELD_OFFSET(CHARFORMAT2A, wWeight));
67 68 69 70
    to->cbSize = sizeof(CHARFORMAT2W);
    return to;
  }

71
  return (from->cbSize >= sizeof(CHARFORMAT2W)) ? from : NULL;
72 73
}

74
static CHARFORMAT2W *ME_ToCFAny(CHARFORMAT2W *to, CHARFORMAT2W *from)
75 76 77 78 79
{
  assert(from->cbSize == sizeof(CHARFORMAT2W));
  if (to->cbSize == sizeof(CHARFORMATA))
  {
    CHARFORMATA *t = (CHARFORMATA *)to;
80
    CopyMemory(t, from, FIELD_OFFSET(CHARFORMATA, szFaceName));
81
    WideCharToMultiByte(0, 0, from->szFaceName, -1, t->szFaceName, sizeof(t->szFaceName), 0, 0);
82 83 84 85 86 87 88 89 90 91 92 93 94 95
    if (from->dwMask & CFM_UNDERLINETYPE)
    {
        switch (from->bUnderlineType)
        {
        case CFU_CF1UNDERLINE:
            to->dwMask |= CFM_UNDERLINE;
            to->dwEffects |= CFE_UNDERLINE;
            break;
        case CFU_UNDERLINENONE:
            to->dwMask |= CFM_UNDERLINE;
            to->dwEffects &= ~CFE_UNDERLINE;
            break;
        }
    }
96 97 98 99 100 101 102
    t->cbSize = sizeof(*t); /* it was overwritten by CopyMemory */
    return to;
  }
  if (to->cbSize == sizeof(CHARFORMATW))
  {
    CHARFORMATW *t = (CHARFORMATW *)to;
    CopyMemory(t, from, sizeof(*t));
103 104 105 106 107 108 109 110 111 112 113 114 115 116
    if (from->dwMask & CFM_UNDERLINETYPE)
    {
        switch (from->bUnderlineType)
        {
        case CFU_CF1UNDERLINE:
            to->dwMask |= CFM_UNDERLINE;
            to->dwEffects |= CFE_UNDERLINE;
            break;
        case CFU_UNDERLINENONE:
            to->dwMask |= CFM_UNDERLINE;
            to->dwEffects &= ~CFE_UNDERLINE;
            break;
        }
    }
117 118 119 120 121 122 123
    t->cbSize = sizeof(*t); /* it was overwritten by CopyMemory */
    return to;
  }
  if (to->cbSize == sizeof(CHARFORMAT2A))
  {
    CHARFORMAT2A *t = (CHARFORMAT2A *)to;
    /* copy the A structure without face name */
124
    CopyMemory(t, from, FIELD_OFFSET(CHARFORMATA, szFaceName));
125 126 127
    /* convert face name */
    WideCharToMultiByte(0, 0, from->szFaceName, -1, t->szFaceName, sizeof(t->szFaceName), 0, 0);
    /* copy the rest of the 2A structure to 2W */
128
    CopyMemory(&t->wWeight, &from->wWeight, sizeof(CHARFORMAT2W)-FIELD_OFFSET(CHARFORMAT2W,wWeight));
129 130 131
    t->cbSize = sizeof(*t); /* it was overwritten by CopyMemory */
    return to;
  }
132
  assert(to->cbSize >= sizeof(CHARFORMAT2W));
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
  return from;
}

void ME_CopyToCFAny(CHARFORMAT2W *to, CHARFORMAT2W *from)
{
  if (ME_ToCFAny(to, from) == from)
    CopyMemory(to, from, to->cbSize);
}

ME_Style *ME_MakeStyle(CHARFORMAT2W *style) {
  CHARFORMAT2W styledata;
  ME_Style *s = ALLOC_OBJ(ME_Style);
  
  style = ME_ToCF2W(&styledata, style);
  memset(s, 0, sizeof(ME_Style));
  if (style->cbSize <= sizeof(CHARFORMAT2W))
    CopyMemory(&s->fmt, style, style->cbSize);
  else
151
    s->fmt = *style;
152 153 154 155 156
  s->fmt.cbSize = sizeof(CHARFORMAT2W);

  s->nSequence = -2;
  s->nRefs = 1;
  s->hFont = NULL;
157
  s->tm.tmAscent = -1;
158
  all_refs++;
159
  TRACE_(richedit_style)("ME_MakeStyle %p, total refs=%d\n", s, all_refs);
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
  return s;
}

#define COPY_STYLE_ITEM(mask, member) \
  if (style->dwMask & mask) { \
    s->fmt.dwMask |= mask;\
    s->fmt.member = style->member;\
  }

#define COPY_STYLE_ITEM_MEMCPY(mask, member) \
  if (style->dwMask & mask) { \
    s->fmt.dwMask |= mask;\
    CopyMemory(s->fmt.member, style->member, sizeof(style->member));\
  }
  
void ME_InitCharFormat2W(CHARFORMAT2W *pFmt)
{
  ZeroMemory(pFmt, sizeof(CHARFORMAT2W));
  pFmt->cbSize = sizeof(CHARFORMAT2W);
}

ME_Style *ME_ApplyStyle(ME_Style *sSrc, CHARFORMAT2W *style)
{
  CHARFORMAT2W styledata;
  ME_Style *s = ME_MakeStyle(&sSrc->fmt);
  style = ME_ToCF2W(&styledata, style);
  COPY_STYLE_ITEM(CFM_ANIMATION, bAnimation);
  COPY_STYLE_ITEM(CFM_BACKCOLOR, crBackColor);
  COPY_STYLE_ITEM(CFM_CHARSET, bCharSet);
  COPY_STYLE_ITEM(CFM_COLOR, crTextColor);
  COPY_STYLE_ITEM_MEMCPY(CFM_FACE, szFaceName);
  COPY_STYLE_ITEM(CFM_KERNING, wKerning);
  COPY_STYLE_ITEM(CFM_LCID, lcid);
  COPY_STYLE_ITEM(CFM_OFFSET, yOffset);
  COPY_STYLE_ITEM(CFM_REVAUTHOR, bRevAuthor);
195 196 197 198
  if (style->dwMask & CFM_SIZE) {
    s->fmt.dwMask |= CFM_SIZE;
    s->fmt.yHeight = min(style->yHeight, yHeightCharPtsMost * 20);
  }
199 200 201 202
  COPY_STYLE_ITEM(CFM_SPACING, sSpacing);
  COPY_STYLE_ITEM(CFM_STYLE, sStyle);
  COPY_STYLE_ITEM(CFM_UNDERLINETYPE, bUnderlineType);
  COPY_STYLE_ITEM(CFM_WEIGHT, wWeight);
203 204 205
  /* FIXME: this is not documented this way, but that's the more logical */
  COPY_STYLE_ITEM(CFM_FACE, bPitchAndFamily);

206 207 208 209 210 211 212 213 214 215
  s->fmt.dwEffects &= ~(style->dwMask);
  s->fmt.dwEffects |= style->dwEffects & style->dwMask;
  s->fmt.dwMask |= style->dwMask;
  if (style->dwMask & CFM_COLOR)
  {
    if (style->dwEffects & CFE_AUTOCOLOR)
      s->fmt.dwEffects |= CFE_AUTOCOLOR;
    else
      s->fmt.dwEffects &= ~CFE_AUTOCOLOR;
  }
216 217 218 219 220 221
  if (style->dwMask & CFM_UNDERLINE)
  {
      s->fmt.dwMask |= CFM_UNDERLINETYPE;
      s->fmt.bUnderlineType = (style->dwEffects & CFM_UNDERLINE) ?
          CFU_CF1UNDERLINE : CFU_UNDERLINENONE;
  }
222 223 224 225 226 227 228 229 230
  if (style->dwMask & CFM_BOLD && !(style->dwMask & CFM_WEIGHT))
  {
      s->fmt.wWeight = (style->dwEffects & CFE_BOLD) ? FW_BOLD : FW_NORMAL;
  } else if (style->dwMask & CFM_WEIGHT && !(style->dwMask & CFM_BOLD)) {
      if (style->wWeight > FW_NORMAL)
          s->fmt.dwEffects |= CFE_BOLD;
      else
          s->fmt.dwEffects &= ~CFE_BOLD;
  }
231 232 233
  return s;
}

234
void ME_CopyCharFormat(CHARFORMAT2W *pDest, const CHARFORMAT2W *pSrc)
235 236 237 238
{
  /* using this with non-2W structs is forbidden */
  assert(pSrc->cbSize == sizeof(CHARFORMAT2W));
  assert(pDest->cbSize == sizeof(CHARFORMAT2W));
239
  *pDest = *pSrc;
240 241
}

242
static void ME_DumpStyleEffect(char **p, const char *name, const CHARFORMAT2W *fmt, int mask)
243 244 245 246 247 248 249 250
{
  *p += sprintf(*p, "%-22s%s\n", name, (fmt->dwMask & mask) ? ((fmt->dwEffects & mask) ? "YES" : "no") : "N/A");
}

void ME_DumpStyle(ME_Style *s)
{
  char buf[2048];
  ME_DumpStyleToBuf(&s->fmt, buf);
251
  TRACE_(richedit_style)("%s\n", buf);
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
}

void ME_DumpStyleToBuf(CHARFORMAT2W *pFmt, char buf[2048])
{
  /* FIXME only CHARFORMAT styles implemented */
  /* this function sucks, doesn't check for buffer overruns but it's "good enough" as for debug code */
  char *p;
  p = buf;
  p += sprintf(p, "Font face:            ");
  if (pFmt->dwMask & CFM_FACE) {
    WCHAR *q = pFmt->szFaceName;
    while(*q) {
      *p++ = (*q > 255) ? '?' : *q;
      q++;      
    }       
  } else
    p += sprintf(p, "N/A");

  if (pFmt->dwMask & CFM_SIZE)
271
    p += sprintf(p, "\nFont size:            %d\n", pFmt->yHeight);
272 273
  else
    p += sprintf(p, "\nFont size:            N/A\n");
274

275
  if (pFmt->dwMask & CFM_OFFSET)
276
    p += sprintf(p, "Char offset:          %d\n", pFmt->yOffset);
277 278 279 280 281 282 283 284 285 286 287 288 289
  else
    p += sprintf(p, "Char offset:          N/A\n");

  if (pFmt->dwMask & CFM_CHARSET)
    p += sprintf(p, "Font charset:         %d\n", (int)pFmt->bCharSet);
  else
    p += sprintf(p, "Font charset:         N/A\n");
    
  /* I'm assuming CFM_xxx and CFE_xxx are the same values, fortunately it IS true wrt used flags*/
  ME_DumpStyleEffect(&p, "Font bold:", pFmt, CFM_BOLD);
  ME_DumpStyleEffect(&p, "Font italic:", pFmt, CFM_ITALIC);
  ME_DumpStyleEffect(&p, "Font underline:", pFmt, CFM_UNDERLINE);
  ME_DumpStyleEffect(&p, "Font strikeout:", pFmt, CFM_STRIKEOUT);
290
  ME_DumpStyleEffect(&p, "Hidden text:", pFmt, CFM_HIDDEN);
291 292 293 294 295 296 297 298 299 300 301 302 303
  p += sprintf(p, "Text color:           ");
  if (pFmt->dwMask & CFM_COLOR)
  {
    if (pFmt->dwEffects & CFE_AUTOCOLOR)
      p += sprintf(p, "auto\n");
    else
      p += sprintf(p, "%06x\n", (int)pFmt->crTextColor);
  }
  else
    p += sprintf(p, "N/A\n");
  ME_DumpStyleEffect(&p, "Text protected:", pFmt, CFM_PROTECTED);
}

304 305

static void
306
ME_LogFontFromStyle(ME_Context* c, LOGFONTW *lf, const ME_Style *s)
307
{
308 309
  ZeroMemory(lf, sizeof(LOGFONTW));
  lstrcpyW(lf->lfFaceName, s->fmt.szFaceName);
310

311
  lf->lfHeight = ME_twips2pointsY(c, -s->fmt.yHeight);
312
  
313
  lf->lfWeight = FW_NORMAL;
314
  if (s->fmt.dwEffects & s->fmt.dwMask & CFM_BOLD)
315
    lf->lfWeight = FW_BOLD;
316
  if (s->fmt.dwMask & CFM_WEIGHT)
317
    lf->lfWeight = s->fmt.wWeight;
318
  if (s->fmt.dwEffects & s->fmt.dwMask & CFM_ITALIC)
319
    lf->lfItalic = 1;
320
  if (s->fmt.dwEffects & s->fmt.dwMask & (CFM_UNDERLINE | CFE_LINK))
321
    lf->lfUnderline = 1;
322 323
  if (s->fmt.dwMask & CFM_UNDERLINETYPE && s->fmt.bUnderlineType == CFU_CF1UNDERLINE)
    lf->lfUnderline = 1;
324
  if (s->fmt.dwEffects & s->fmt.dwMask & CFM_STRIKEOUT)
325
    lf->lfStrikeOut = 1;
326 327
  if (s->fmt.dwEffects & s->fmt.dwMask & (CFM_SUBSCRIPT|CFM_SUPERSCRIPT))
    lf->lfHeight = (lf->lfHeight*2)/3;
328
/*lf.lfQuality = PROOF_QUALITY; */
329 330
  if (s->fmt.dwMask & CFM_FACE)
    lf->lfPitchAndFamily = s->fmt.bPitchAndFamily;
331 332
  if (s->fmt.dwMask & CFM_CHARSET)
    lf->lfCharSet = s->fmt.bCharSet;
333 334
}

335
void ME_CharFormatFromLogFont(HDC hDC, const LOGFONTW *lf, CHARFORMAT2W *fmt)
336
{
337
  int ry;
338

339 340 341 342 343 344 345
  ME_InitCharFormat2W(fmt);
  ry = GetDeviceCaps(hDC, LOGPIXELSY);
  lstrcpyW(fmt->szFaceName, lf->lfFaceName);
  fmt->dwEffects = 0;
  fmt->dwMask = CFM_WEIGHT|CFM_BOLD|CFM_ITALIC|CFM_UNDERLINE|CFM_STRIKEOUT|CFM_SIZE|CFM_FACE|CFM_CHARSET;
  fmt->wWeight = lf->lfWeight;
  fmt->yHeight = -lf->lfHeight*1440/ry;
346
  if (lf->lfWeight > FW_NORMAL) fmt->dwEffects |= CFM_BOLD;
347 348
  if (lf->lfItalic) fmt->dwEffects |= CFM_ITALIC;
  if (lf->lfUnderline) fmt->dwEffects |= CFM_UNDERLINE;
349
  /* notice that if a logfont was created with underline due to CFM_LINK, this
Austin English's avatar
Austin English committed
350
      would add an erroneous CFM_UNDERLINE. This isn't currently ever a problem. */
351 352
  if (lf->lfStrikeOut) fmt->dwEffects |= CFM_STRIKEOUT;
  fmt->bPitchAndFamily = lf->lfPitchAndFamily;
353
  fmt->bCharSet = lf->lfCharSet;
354
}
355

356
static BOOL ME_IsFontEqual(const LOGFONTW *p1, const LOGFONTW *p2)
357 358 359 360 361 362
{
  if (memcmp(p1, p2, sizeof(LOGFONTW)-sizeof(p1->lfFaceName)))
    return FALSE;
  if (lstrcmpW(p1->lfFaceName, p2->lfFaceName))
    return FALSE;
  return TRUE;
363 364
}

365
HFONT ME_SelectStyleFont(ME_Context *c, ME_Style *s)
366 367
{
  HFONT hOldFont;
368 369 370 371 372
  LOGFONTW lf;
  int i, nEmpty, nAge = 0x7FFFFFFF;
  ME_FontCacheItem *item;
  assert(s);
  
373
  ME_LogFontFromStyle(c, &lf, s);
374 375
  
  for (i=0; i<HFONT_CACHE_SIZE; i++)
376
    c->editor->pFontCache[i].nAge++;
377 378
  for (i=0, nEmpty=-1, nAge=0; i<HFONT_CACHE_SIZE; i++)
  {
379
    item = &c->editor->pFontCache[i];
380 381 382 383 384
    if (!item->nRefs)
    {
      if (item->nAge > nAge)
        nEmpty = i, nAge = item->nAge;
    }
385
    if (item->hFont && ME_IsFontEqual(&item->lfSpecs, &lf))
386 387 388 389
      break;
  }
  if (i < HFONT_CACHE_SIZE) /* found */
  {
390
    item = &c->editor->pFontCache[i];
391
    TRACE_(richedit_style)("font reused %d\n", i);
392 393 394 395 396 397

    s->hFont = item->hFont;
    item->nRefs++;
  }
  else
  {
398
    item = &c->editor->pFontCache[nEmpty]; /* this legal even when nEmpty == -1, as we don't dereference it */
399 400 401

    assert(nEmpty != -1); /* otherwise we leak cache entries or get too many fonts at once*/
    if (item->hFont) {
402
      TRACE_(richedit_style)("font deleted %d\n", nEmpty);
403 404 405 406 407
      DeleteObject(item->hFont);
      item->hFont = NULL;
    }
    s->hFont = CreateFontIndirectW(&lf);
    assert(s->hFont);
408
    TRACE_(richedit_style)("font created %d\n", nEmpty);
409 410
    item->hFont = s->hFont;
    item->nRefs = 1;
411
    item->lfSpecs = lf;
412
  }
413
  hOldFont = SelectObject(c->hDC, s->hFont);
414
  /* should be cached too, maybe ? */
415
  GetTextMetricsW(c->hDC, &s->tm);
416 417 418
  return hOldFont;
}

419
void ME_UnselectStyleFont(ME_Context *c, ME_Style *s, HFONT hOldFont)
420
{
421 422 423
  int i;
  
  assert(s);
424
  SelectObject(c->hDC, hOldFont);
425 426
  for (i=0; i<HFONT_CACHE_SIZE; i++)
  {
427
    ME_FontCacheItem *pItem = &c->editor->pFontCache[i];
428 429 430 431 432 433 434 435 436
    if (pItem->hFont == s->hFont && pItem->nRefs > 0)
    {
      pItem->nRefs--;
      pItem->nAge = 0;
      s->hFont = NULL;
      return;
    }
  }
  assert(0 == "UnselectStyleFont without SelectStyleFont");
437 438
}

439
static void ME_DestroyStyle(ME_Style *s) {
440 441 442 443 444 445 446 447 448 449 450 451 452
  if (s->hFont)
  {
    DeleteObject(s->hFont);
    s->hFont = NULL;
  }
  FREE_OBJ(s);
}

void ME_AddRefStyle(ME_Style *s)
{
  assert(s->nRefs>0); /* style with 0 references isn't supposed to exist */
  s->nRefs++;
  all_refs++;
453
  TRACE_(richedit_style)("ME_AddRefStyle %p, new refs=%d, total refs=%d\n", s, s->nRefs, all_refs);
454 455 456 457 458 459 460
}

void ME_ReleaseStyle(ME_Style *s)
{
  s->nRefs--;
  all_refs--;
  if (s->nRefs==0)
461
    TRACE_(richedit_style)("destroy style %p, total refs=%d\n", s, all_refs);
462
  else
463
    TRACE_(richedit_style)("release style %p, new refs=%d, total refs=%d\n", s, s->nRefs, all_refs);
464
  if (!all_refs) TRACE("all style references freed (good!)\n");
465 466 467 468 469
  assert(s->nRefs>=0);
  if (!s->nRefs)
    ME_DestroyStyle(s);
}

470 471
ME_Style *ME_GetInsertStyle(ME_TextEditor *editor, int nCursor)
{
472 473
  if (ME_IsSelection(editor))
  {
474 475
    ME_Cursor *from, *to;

476
    ME_GetSelection(editor, &from, &to);
477 478
    ME_AddRefStyle(from->pRun->member.run.style);
    return from->pRun->member.run.style;
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521
  }
  if (editor->pBuffer->pCharStyle) {
    ME_AddRefStyle(editor->pBuffer->pCharStyle);
    return editor->pBuffer->pCharStyle;
  }
  else
  {
    ME_Cursor *pCursor = &editor->pCursors[nCursor];
    ME_DisplayItem *pRunItem = pCursor->pRun;
    ME_DisplayItem *pPrevItem = NULL;
    if (pCursor->nOffset) {
      ME_Run *pRun = &pRunItem->member.run;
      ME_AddRefStyle(pRun->style);
      return pRun->style;
    }
    pPrevItem = ME_FindItemBack(pRunItem, diRunOrParagraph);
    if (pPrevItem->type == diRun)
    {
      ME_AddRefStyle(pPrevItem->member.run.style);
      return pPrevItem->member.run.style;
    }
    else
    {
      ME_AddRefStyle(pRunItem->member.run.style);
      return pRunItem->member.run.style;
    }
  }
}

void ME_SaveTempStyle(ME_TextEditor *editor)
{
  ME_Style *old_style = editor->pBuffer->pCharStyle;
  editor->pBuffer->pCharStyle = ME_GetInsertStyle(editor, 0);
  if (old_style)
    ME_ReleaseStyle(old_style);
}

void ME_ClearTempStyle(ME_TextEditor *editor)
{
  if (!editor->pBuffer->pCharStyle) return;
  ME_ReleaseStyle(editor->pBuffer->pCharStyle);
  editor->pBuffer->pCharStyle = NULL;
}