- made string operations consistent wrt whitespace handling (which
[wine/gsoc_dplay.git] / dlls / riched20 / run.c
blob6440b6d37e60c0982cd98167b6eb793cdf52258e
1 /*
2 * RichEdit - operations on runs (diRun, rectangular pieces of paragraphs).
3 * Splitting/joining runs. Adjusting offsets after deleting/adding content.
4 * Character/pixel conversions.
6 * Copyright 2004 by Krzysztof Foltman
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "editor.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(richedit);
27 int ME_CanJoinRuns(ME_Run *run1, ME_Run *run2)
29 if ((run1->nFlags | run2->nFlags) & (MERF_ENDPARA | MERF_GRAPHICS))
30 return 0;
31 if (run1->style != run2->style)
32 return 0;
33 if ((run1->nFlags & MERF_STYLEFLAGS) != (run2->nFlags & MERF_STYLEFLAGS))
34 return 0;
35 return 1;
38 void ME_SkipAndPropagateCharOffset(ME_DisplayItem *p, int shift)
40 p = ME_FindItemFwd(p, diRunOrParagraphOrEnd);
41 assert(p);
42 ME_PropagateCharOffset(p, shift);
45 void ME_PropagateCharOffset(ME_DisplayItem *p, int shift)
47 if (p->type == diRun) /* propagate in all runs in this para */
49 TRACE("PropagateCharOffset(%s, %d)\n", debugstr_w(p->member.run.strText->szData), shift);
50 do {
51 p->member.run.nCharOfs += shift;
52 assert(p->member.run.nCharOfs >= 0);
53 p = ME_FindItemFwd(p, diRunOrParagraphOrEnd);
54 } while(p->type == diRun);
56 if (p->type == diParagraph) /* propagate in all next paras */
58 do {
59 p->member.para.nCharOfs += shift;
60 assert(p->member.para.nCharOfs >= 0);
61 p = p->member.para.next_para;
62 } while(p->type == diParagraph);
64 if (p->type == diTextEnd)
66 p->member.para.nCharOfs += shift;
67 assert(p->member.para.nCharOfs >= 0);
71 void ME_CheckCharOffsets(ME_TextEditor *editor)
73 ME_DisplayItem *p = editor->pBuffer->pFirst;
74 int ofs = 0, ofsp = 0;
75 if(TRACE_ON(richedit))
77 TRACE("---\n");
78 ME_DumpDocument(editor->pBuffer);
80 do {
81 p = ME_FindItemFwd(p, diRunOrParagraphOrEnd);
82 switch(p->type) {
83 case diTextEnd:
84 TRACE("tend, real ofsp = %d, counted = %d\n", p->member.para.nCharOfs, ofsp+ofs);
85 assert(ofsp+ofs == p->member.para.nCharOfs);
86 return;
87 case diParagraph:
88 TRACE("para, real ofsp = %d, counted = %d\n", p->member.para.nCharOfs, ofsp+ofs);
89 assert(ofsp+ofs == p->member.para.nCharOfs);
90 ofsp = p->member.para.nCharOfs;
91 ofs = 0;
92 break;
93 case diRun:
94 TRACE("run, real ofs = %d (+ofsp = %d), counted = %d, len = %d, txt = \"%s\", flags=%08x, fx&mask = %08lx\n",
95 p->member.run.nCharOfs, p->member.run.nCharOfs+ofsp, ofsp+ofs,
96 p->member.run.strText->nLen, debugstr_w(p->member.run.strText->szData),
97 p->member.run.nFlags,
98 p->member.run.style->fmt.dwMask & p->member.run.style->fmt.dwEffects);
99 assert(ofs == p->member.run.nCharOfs);
100 ofs += ME_StrLen(p->member.run.strText);
101 break;
102 default:
103 assert(0);
105 } while(1);
108 int ME_CharOfsFromRunOfs(ME_TextEditor *editor, ME_DisplayItem *pRun, int nOfs)
110 ME_DisplayItem *pPara;
112 assert(pRun->type == diRun);
113 assert(pRun->member.run.nCharOfs != -1);
115 pPara = ME_FindItemBack(pRun, diParagraph);
116 assert(pPara);
117 assert(pPara->type==diParagraph);
118 return pPara->member.para.nCharOfs + pRun->member.run.nCharOfs
119 + ME_VPosToPos(pRun->member.run.strText, nOfs);
122 void ME_CursorFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_Cursor *pCursor)
124 ME_RunOfsFromCharOfs(editor, nCharOfs, &pCursor->pRun, &pCursor->nOffset);
127 void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **ppRun, int *pOfs)
129 ME_DisplayItem *pPara;
130 int nParaOfs;
132 pPara = editor->pBuffer->pFirst->member.para.next_para;
133 assert(pPara);
134 assert(ppRun);
135 assert(pOfs);
136 while (pPara->type == diParagraph)
138 nParaOfs = pPara->member.para.nCharOfs;
139 assert(nCharOfs >= nParaOfs);
141 if (nCharOfs < pPara->member.para.next_para->member.para.nCharOfs)
143 *ppRun = ME_FindItemFwd(pPara, diRun);
144 assert(*ppRun);
145 while (!((*ppRun)->member.run.nFlags & MERF_ENDPARA))
147 ME_DisplayItem *pNext = ME_FindItemFwd(*ppRun, diRun);
148 assert(pNext);
149 assert(pNext->type == diRun);
150 if (nCharOfs < nParaOfs + pNext->member.run.nCharOfs) {
151 *pOfs = ME_PosToVPos((*ppRun)->member.run.strText,
152 nCharOfs - nParaOfs - (*ppRun)->member.run.nCharOfs);
153 return;
155 *ppRun = pNext;
157 if (nCharOfs == nParaOfs + (*ppRun)->member.run.nCharOfs) {
158 *pOfs = 0;
159 return;
162 pPara = pPara->member.para.next_para;
164 *ppRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
165 *pOfs = 0;
166 assert((*ppRun)->member.run.nFlags & MERF_ENDPARA);
169 void ME_JoinRuns(ME_TextEditor *editor, ME_DisplayItem *p)
171 ME_DisplayItem *pNext = p->next;
172 int i;
173 assert(p->type == diRun && pNext->type == diRun);
174 assert(p->member.run.nCharOfs != -1);
175 ME_GetParagraph(p)->member.para.nFlags |= MEPF_REWRAP;
177 if (editor->bCaretAtEnd && editor->pCursors[0].pRun == pNext)
178 editor->bCaretAtEnd = FALSE;
179 for (i=0; i<editor->nCursors; i++) {
180 if (editor->pCursors[i].pRun == pNext) {
181 editor->pCursors[i].pRun = p;
182 editor->pCursors[i].nOffset += ME_StrVLen(p->member.run.strText);
186 ME_AppendString(p->member.run.strText, pNext->member.run.strText);
187 ME_Remove(pNext);
188 ME_DestroyDisplayItem(pNext);
189 ME_UpdateRunFlags(editor, &p->member.run);
190 if(TRACE_ON(richedit))
192 TRACE("Before check after join\n");
193 ME_CheckCharOffsets(editor);
194 TRACE("After check after join\n");
198 ME_DisplayItem *ME_SplitRun(ME_Context *c, ME_DisplayItem *item, int nVChar)
200 ME_TextEditor *editor = c->editor;
201 ME_DisplayItem *item2 = NULL;
202 ME_Run *run, *run2;
204 assert(item->member.run.nCharOfs != -1);
205 if(TRACE_ON(richedit))
207 TRACE("Before check before split\n");
208 ME_CheckCharOffsets(editor);
209 TRACE("After check before split\n");
212 run = &item->member.run;
214 TRACE("Before split: %s(%ld, %ld)\n", debugstr_w(run->strText->szData),
215 run->pt.x, run->pt.y);
217 item2 = ME_SplitRunSimple(editor, item, nVChar);
219 run2 = &item2->member.run;
221 ME_CalcRunExtent(c, run);
222 ME_CalcRunExtent(c, run2);
224 run2->pt.x = run->pt.x+run->nWidth;
225 run2->pt.y = run->pt.y;
227 if(TRACE_ON(richedit))
229 TRACE("Before check after split\n");
230 ME_CheckCharOffsets(editor);
231 TRACE("After check after split\n");
232 TRACE("After split: %s(%ld, %ld), %s(%ld, %ld)\n",
233 debugstr_w(run->strText->szData), run->pt.x, run->pt.y,
234 debugstr_w(run2->strText->szData), run2->pt.x, run2->pt.y);
237 return item2;
240 /* split a run starting from voffset */
241 ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, int nVChar)
243 ME_Run *run = &item->member.run;
244 ME_DisplayItem *item2;
245 ME_Run *run2;
246 int i;
247 assert(nVChar > 0 && nVChar < ME_StrVLen(run->strText));
248 assert(item->type == diRun);
249 assert(!(item->member.run.nFlags & MERF_GRAPHICS));
250 assert(item->member.run.nCharOfs != -1);
252 item2 = ME_MakeRun(run->style,
253 ME_VSplitString(run->strText, nVChar), run->nFlags&MERF_SPLITMASK);
255 item2->member.run.nCharOfs = item->member.run.nCharOfs+
256 ME_VPosToPos(item->member.run.strText, nVChar);
258 run2 = &item2->member.run;
259 ME_InsertBefore(item->next, item2);
261 ME_UpdateRunFlags(editor, run);
262 ME_UpdateRunFlags(editor, run2);
263 for (i=0; i<editor->nCursors; i++) {
264 if (editor->pCursors[i].pRun == item &&
265 editor->pCursors[i].nOffset >= nVChar) {
266 assert(item2->type == diRun);
267 editor->pCursors[i].pRun = item2;
268 editor->pCursors[i].nOffset -= nVChar;
271 ME_GetParagraph(item)->member.para.nFlags |= MEPF_REWRAP;
272 return item2;
275 /* split the start and final whitespace into separate runs */
276 /* returns the last run added */
278 ME_DisplayItem *ME_SplitFurther(ME_TextEditor *editor, ME_DisplayItem *item)
280 int i, nVLen, nChanged;
281 assert(item->type == diRun);
282 assert(!(item->member.run.nFlags & MERF_GRAPHICS));
283 return item;
287 ME_DisplayItem *ME_MakeRun(ME_Style *s, ME_String *strData, int nFlags)
289 ME_DisplayItem *item = ME_MakeDI(diRun);
290 item->member.run.style = s;
291 item->member.run.strText = strData;
292 item->member.run.nFlags = nFlags;
293 item->member.run.nCharOfs = -1;
294 ME_AddRefStyle(s);
295 return item;
298 ME_DisplayItem *ME_InsertRun(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem *pItem)
300 ME_Cursor tmp;
301 ME_DisplayItem *pDI;
302 ME_UndoItem *pUI;
304 assert(pItem->type == diRun || pItem->type == diUndoInsertRun);
306 pUI = ME_AddUndoItem(editor, diUndoDeleteRun, NULL);
307 if (pUI) {
308 pUI->nStart = nCharOfs;
309 pUI->nLen = pItem->member.run.strText->nLen;
311 ME_CursorFromCharOfs(editor, nCharOfs, &tmp);
312 if (tmp.nOffset) {
313 tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset);
314 tmp.nOffset = 0;
316 pDI = ME_MakeRun(pItem->member.run.style, ME_StrDup(pItem->member.run.strText), pItem->member.run.nFlags);
317 pDI->member.run.nCharOfs = tmp.pRun->member.run.nCharOfs;
318 ME_InsertBefore(tmp.pRun, pDI);
319 TRACE("Shift length:%d\n", pDI->member.run.strText->nLen);
320 ME_PropagateCharOffset(tmp.pRun, pDI->member.run.strText->nLen);
321 ME_GetParagraph(tmp.pRun)->member.para.nFlags |= MEPF_REWRAP;
323 return pDI;
326 void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run)
328 assert(run->nCharOfs != -1);
329 if (ME_IsSplitable(run->strText))
330 run->nFlags |= MERF_SPLITTABLE;
331 else
332 run->nFlags &= ~MERF_SPLITTABLE;
334 if (!(run->nFlags & MERF_GRAPHICS)) {
335 if (ME_IsWhitespaces(run->strText))
336 run->nFlags |= MERF_WHITESPACE | MERF_STARTWHITE | MERF_ENDWHITE;
337 else
339 run->nFlags &= ~MERF_WHITESPACE;
341 if (ME_IsWSpace(ME_GetCharFwd(run->strText,0)))
342 run->nFlags |= MERF_STARTWHITE;
343 else
344 run->nFlags &= ~MERF_STARTWHITE;
346 if (ME_IsWSpace(ME_GetCharBack(run->strText,0)))
347 run->nFlags |= MERF_ENDWHITE;
348 else
349 run->nFlags &= ~MERF_ENDWHITE;
352 else
353 run->nFlags &= ~(MERF_WHITESPACE | MERF_STARTWHITE | MERF_ENDWHITE);
356 void ME_GetGraphicsSize(ME_TextEditor *editor, ME_Run *run, SIZE *pSize)
358 assert(run->nFlags & MERF_GRAPHICS);
359 pSize->cx = 64;
360 pSize->cy = 64;
363 int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run)
365 int fit = 0;
366 HGDIOBJ hOldFont;
367 HDC hDC;
368 SIZE sz;
369 if (!run->strText->nLen)
370 return 0;
372 if (run->nFlags & MERF_GRAPHICS)
374 SIZE sz;
375 ME_GetGraphicsSize(editor, run, &sz);
376 if (cx < sz.cx)
377 return 0;
378 return 1;
380 hDC = GetDC(editor->hWnd);
381 hOldFont = ME_SelectStyleFont(editor, hDC, run->style);
382 GetTextExtentExPointW(hDC, run->strText->szData, run->strText->nLen,
383 cx, &fit, NULL, &sz);
384 ME_UnselectStyleFont(editor, hDC, run->style, hOldFont);
385 ReleaseDC(editor->hWnd, hDC);
386 return fit;
389 int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run)
391 int fit = 0, fit1 = 0;
392 HGDIOBJ hOldFont;
393 HDC hDC;
394 SIZE sz, sz2, sz3;
395 if (!run->strText->nLen)
396 return 0;
398 if (run->nFlags & MERF_GRAPHICS)
400 SIZE sz;
401 ME_GetGraphicsSize(editor, run, &sz);
402 if (cx < sz.cx/2)
403 return 0;
404 return 1;
407 hDC = GetDC(editor->hWnd);
408 hOldFont = ME_SelectStyleFont(editor, hDC, run->style);
409 GetTextExtentExPointW(hDC, run->strText->szData, run->strText->nLen,
410 cx, &fit, NULL, &sz);
411 if (fit != run->strText->nLen)
413 int chars = 1;
415 GetTextExtentPoint32W(hDC, run->strText->szData, fit, &sz2);
416 fit1 = ME_StrRelPos(run->strText, fit, &chars);
417 GetTextExtentPoint32W(hDC, run->strText->szData, fit1, &sz3);
418 if (cx >= (sz2.cx+sz3.cx)/2)
419 fit = fit1;
421 ME_UnselectStyleFont(editor, hDC, run->style, hOldFont);
422 ReleaseDC(editor->hWnd, hDC);
423 return fit;
426 int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset)
428 SIZE size;
429 HDC hDC = GetDC(editor->hWnd);
430 HGDIOBJ hOldFont;
432 if (pRun->nFlags & MERF_GRAPHICS)
434 if (!nOffset) return 0;
435 ME_GetGraphicsSize(editor, pRun, &size);
436 return 1;
438 hOldFont = ME_SelectStyleFont(editor, hDC, pRun->style);
439 GetTextExtentPoint32W(hDC, pRun->strText->szData, nOffset, &size);
440 ME_UnselectStyleFont(editor, hDC, pRun->style, hOldFont);
441 ReleaseDC(editor->hWnd, hDC);
442 return size.cx;
445 void ME_GetTextExtent(ME_Context *c, LPCWSTR szText, int nChars, ME_Style *s,
446 SIZE *size)
448 HDC hDC = c->hDC;
449 HGDIOBJ hOldFont;
450 hOldFont = ME_SelectStyleFont(c->editor, hDC, s);
451 GetTextExtentPoint32W(hDC, szText, nChars, size);
452 ME_UnselectStyleFont(c->editor, hDC, s, hOldFont);
455 SIZE ME_GetRunSize(ME_Context *c, ME_Run *run, int nLen)
457 SIZE size;
458 int nMaxLen = ME_StrVLen(run->strText);
460 if (nLen>nMaxLen)
461 nLen = nMaxLen;
463 if (run->nFlags & MERF_GRAPHICS)
465 ME_GetGraphicsSize(c->editor, run, &size);
466 return size;
469 ME_GetTextExtent(c, run->strText->szData, nLen, run->style, &size);
471 return size;
474 void ME_CalcRunExtent(ME_Context *c, ME_Run *run)
476 SIZE size;
477 int nEnd = ME_StrVLen(run->strText);
479 if (run->nFlags & MERF_GRAPHICS) {
480 ME_GetGraphicsSize(c->editor, run, &size);
481 run->nWidth = size.cx;
482 run->nAscent = size.cy;
483 run->nDescent = 0;
484 return;
486 ME_GetTextExtent(c, run->strText->szData, nEnd, run->style, &size);
487 run->nWidth = size.cx;
488 run->nAscent = run->style->tm.tmAscent;
489 run->nDescent = run->style->tm.tmDescent;
492 void ME_MustBeWrapped(ME_Context *c, ME_DisplayItem *para)
494 assert(para->type == diParagraph);
495 /* FIXME */
498 void ME_SetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
500 int nFrom, nTo;
501 ME_GetSelection(editor, &nFrom, &nTo);
502 if (nFrom == nTo)
504 ME_Style *s;
505 if (!editor->pBuffer->pCharStyle)
506 editor->pBuffer->pCharStyle = ME_GetInsertStyle(editor, 0);
507 s = ME_ApplyStyle(editor->pBuffer->pCharStyle, pFmt);
508 ME_ReleaseStyle(editor->pBuffer->pCharStyle);
509 editor->pBuffer->pCharStyle = s;
511 else
512 ME_SetCharFormat(editor, nFrom, nTo-nFrom, pFmt);
515 void ME_SetCharFormat(ME_TextEditor *editor, int nOfs, int nChars, CHARFORMAT2W *pFmt)
517 ME_Cursor tmp, tmp2;
518 ME_DisplayItem *para;
520 ME_CursorFromCharOfs(editor, nOfs, &tmp);
521 if (tmp.nOffset)
522 tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset);
524 ME_CursorFromCharOfs(editor, nOfs+nChars, &tmp2);
525 if (tmp2.nOffset)
526 tmp2.pRun = ME_SplitRunSimple(editor, tmp2.pRun, tmp2.nOffset);
528 para = ME_GetParagraph(tmp.pRun);
529 para->member.para.nFlags |= MEPF_REWRAP;
531 while(tmp.pRun != tmp2.pRun)
533 ME_UndoItem *undo = NULL;
534 ME_Style *new_style = ME_ApplyStyle(tmp.pRun->member.run.style, pFmt);
535 /* ME_DumpStyle(new_style); */
536 undo = ME_AddUndoItem(editor, diUndoSetCharFormat, NULL);
537 if (undo) {
538 undo->nStart = tmp.pRun->member.run.nCharOfs+para->member.para.nCharOfs;
539 undo->nLen = tmp.pRun->member.run.strText->nLen;
540 undo->di.member.ustyle = tmp.pRun->member.run.style;
541 /* we'd have to addref undo..ustyle and release tmp...style
542 but they'd cancel each other out so we can do nothing instead */
544 else
545 ME_ReleaseStyle(tmp.pRun->member.run.style);
546 tmp.pRun->member.run.style = new_style;
547 tmp.pRun = ME_FindItemFwd(tmp.pRun, diRunOrParagraph);
548 if (tmp.pRun->type == diParagraph)
550 para = tmp.pRun;
551 tmp.pRun = ME_FindItemFwd(tmp.pRun, diRun);
552 if (tmp.pRun != tmp2.pRun)
553 para->member.para.nFlags |= MEPF_REWRAP;
555 assert(tmp.pRun);
559 void ME_SetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *mod)
561 ME_Style *style;
562 ME_UndoItem *undo;
564 assert(mod->cbSize == sizeof(CHARFORMAT2W));
565 undo = ME_AddUndoItem(editor, diUndoSetDefaultCharFormat, NULL);
566 if (undo) {
567 undo->nStart = -1;
568 undo->nLen = -1;
569 undo->di.member.ustyle = editor->pBuffer->pDefaultStyle;
570 ME_AddRefStyle(undo->di.member.ustyle);
572 style = ME_ApplyStyle(editor->pBuffer->pDefaultStyle, mod);
573 editor->pBuffer->pDefaultStyle->fmt = style->fmt;
574 editor->pBuffer->pDefaultStyle->tm = style->tm;
575 ME_ReleaseStyle(style);
576 ME_MarkAllForWrapping(editor);
577 /* pcf = editor->pBuffer->pDefaultStyle->fmt; */
580 void ME_GetRunCharFormat(ME_TextEditor *editor, ME_DisplayItem *run, CHARFORMAT2W *pFmt)
582 ME_CopyCharFormat(pFmt, &run->member.run.style->fmt);
585 void ME_GetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
587 int nFrom, nTo;
588 ME_GetSelection(editor, &nFrom, &nTo);
589 ME_CopyCharFormat(pFmt, &editor->pBuffer->pDefaultStyle->fmt);
592 void ME_GetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
594 int nFrom, nTo;
595 ME_GetSelection(editor, &nFrom, &nTo);
596 if (nFrom == nTo && editor->pBuffer->pCharStyle)
598 ME_CopyCharFormat(pFmt, &editor->pBuffer->pCharStyle->fmt);
599 return;
601 ME_GetCharFormat(editor, nFrom, nTo, pFmt);
604 void ME_GetCharFormat(ME_TextEditor *editor, int nFrom, int nTo, CHARFORMAT2W *pFmt)
606 ME_DisplayItem *run, *run_end;
607 int nOffset, nOffset2;
608 CHARFORMAT2W tmp;
610 if (nTo>nFrom) /* selection consists of chars from nFrom up to nTo-1 */
611 nTo--;
613 ME_RunOfsFromCharOfs(editor, nFrom, &run, &nOffset);
614 if (nFrom == nTo) /* special case - if selection is empty, take previous char's formatting */
616 if (!nOffset)
618 ME_DisplayItem *tmp_run = ME_FindItemBack(run, diRunOrParagraph);
619 if (tmp_run->type == diRun) {
620 ME_GetRunCharFormat(editor, tmp_run, pFmt);
621 return;
624 ME_GetRunCharFormat(editor, run, pFmt);
625 return;
627 ME_RunOfsFromCharOfs(editor, nTo, &run_end, &nOffset2);
629 ME_GetRunCharFormat(editor, run, pFmt);
631 if (run == run_end) return;
633 do {
634 /* FIXME add more style feature comparisons */
635 int nAttribs = CFM_SIZE | CFM_FACE | CFM_COLOR;
636 int nEffects = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE;
638 run = ME_FindItemFwd(run, diRun);
640 ZeroMemory(&tmp, sizeof(tmp));
641 tmp.cbSize = sizeof(tmp);
642 ME_GetRunCharFormat(editor, run, &tmp);
644 assert((tmp.dwMask & nAttribs) == nAttribs);
645 assert((tmp.dwMask & nEffects) == nEffects);
646 /* reset flags that differ */
648 if (pFmt->yHeight != tmp.yHeight)
649 pFmt->dwMask &= ~CFM_SIZE;
650 if (pFmt->dwMask & CFM_FACE)
652 if (!(tmp.dwMask & CFM_FACE))
653 pFmt->dwMask &= ~CFM_FACE;
654 else if (lstrcmpW(pFmt->szFaceName, tmp.szFaceName))
655 pFmt->dwMask &= ~CFM_FACE;
657 if (pFmt->yHeight != tmp.yHeight)
658 pFmt->dwMask &= ~CFM_SIZE;
659 if (pFmt->dwMask & CFM_COLOR)
661 if (!((pFmt->dwEffects&CFE_AUTOCOLOR) & (tmp.dwEffects&CFE_AUTOCOLOR)))
663 if (pFmt->crTextColor != tmp.crTextColor)
664 pFmt->dwMask &= ~CFM_COLOR;
668 pFmt->dwMask &= ~((pFmt->dwEffects ^ tmp.dwEffects) & nEffects);
670 } while(run != run_end);