ReactOS 0.4.15-dev-7924-g5949c20
run.c
Go to the documentation of this file.
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.
5 *
6 * Copyright 2004 by Krzysztof Foltman
7 * Copyright 2006 by Phil Krylov
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include "editor.h"
25
29
30/******************************************************************************
31 * ME_CanJoinRuns
32 *
33 * Returns TRUE if two runs can be safely merged into one, FALSE otherwise.
34 */
35BOOL ME_CanJoinRuns(const ME_Run *run1, const ME_Run *run2)
36{
37 if ((run1->nFlags | run2->nFlags) & MERF_NOJOIN)
38 return FALSE;
39 if (run1->style != run2->style)
40 return FALSE;
41 if ((run1->nFlags & MERF_STYLEFLAGS) != (run2->nFlags & MERF_STYLEFLAGS))
42 return FALSE;
43 return TRUE;
44}
45
47{
49 assert(p);
51}
52
53/******************************************************************************
54 * ME_PropagateCharOffsets
55 *
56 * Shifts (increases or decreases) character offset (relative to beginning of
57 * the document) of the part of the text starting from given place.
58 */
60{
61 /* Runs in one paragraph contain character offset relative to their owning
62 * paragraph. If we start the shifting from the run, we need to shift
63 * all the relative offsets until the end of the paragraph
64 */
65 if (p->type == diRun) /* propagate in all runs in this para */
66 {
67 TRACE("PropagateCharOffset(%s, %d)\n", debugstr_run( &p->member.run ), shift);
68 do {
69 p->member.run.nCharOfs += shift;
70 assert(p->member.run.nCharOfs >= 0);
72 } while(p->type == diRun);
73 }
74 /* Runs in next paragraphs don't need their offsets updated, because they,
75 * again, those offsets are relative to their respective paragraphs.
76 * Instead of that, we're updating paragraphs' character offsets.
77 */
78 if (p->type == diParagraph) /* propagate in all next paras */
79 {
80 do {
81 p->member.para.nCharOfs += shift;
82 assert(p->member.para.nCharOfs >= 0);
83 p = p->member.para.next_para;
84 } while(p->type == diParagraph);
85 }
86 /* diTextEnd also has character offset in it, which makes finding text length
87 * easier. But it needs to be up to date first.
88 */
89 if (p->type == diTextEnd)
90 {
91 p->member.para.nCharOfs += shift;
92 assert(p->member.para.nCharOfs >= 0);
93 }
94}
95
96/******************************************************************************
97 * ME_CheckCharOffsets
98 *
99 * Checks if editor lists' validity and optionally dumps the document structure
100 */
102{
103 ME_DisplayItem *p = editor->pBuffer->pFirst;
104 int ofs = 0, ofsp = 0;
105
106 if (!TRACE_ON(richedit_check))
107 return;
108
109 TRACE_(richedit_check)("Checking begin\n");
110 if(TRACE_ON(richedit_lists))
111 {
112 TRACE_(richedit_lists)("---\n");
113 ME_DumpDocument(editor->pBuffer);
114 }
115 do {
117 switch(p->type) {
118 case diTextEnd:
119 TRACE_(richedit_check)("tend, real ofsp = %d, counted = %d\n", p->member.para.nCharOfs, ofsp+ofs);
120 assert(ofsp+ofs == p->member.para.nCharOfs);
121 TRACE_(richedit_check)("Checking finished\n");
122 return;
123 case diParagraph:
124 TRACE_(richedit_check)("para, real ofsp = %d, counted = %d\n", p->member.para.nCharOfs, ofsp+ofs);
125 assert(ofsp+ofs == p->member.para.nCharOfs);
126 ofsp = p->member.para.nCharOfs;
127 ofs = 0;
128 break;
129 case diRun:
130 TRACE_(richedit_check)("run, real ofs = %d (+ofsp = %d), counted = %d, len = %d, txt = %s, flags=%08x, fx&mask = %08x\n",
131 p->member.run.nCharOfs, p->member.run.nCharOfs+ofsp, ofsp+ofs,
132 p->member.run.len, debugstr_run( &p->member.run ),
133 p->member.run.nFlags,
134 p->member.run.style->fmt.dwMask & p->member.run.style->fmt.dwEffects);
135 assert(ofs == p->member.run.nCharOfs);
136 assert(p->member.run.len);
137 ofs += p->member.run.len;
138 break;
139 case diCell:
140 TRACE_(richedit_check)("cell\n");
141 break;
142 default:
143 assert(0);
144 }
145 } while(1);
146 TRACE_(richedit_check)("Checking finished\n");
147}
148
149/******************************************************************************
150 * ME_CharOfsFromRunOfs
151 *
152 * Converts a character position relative to the start of the run, to a
153 * character position relative to the start of the document.
154 * Kind of a "local to global" offset conversion.
155 */
157 const ME_DisplayItem *pRun, int nOfs)
158{
159 assert(pRun && pRun->type == diRun);
160 assert(pPara && pPara->type == diParagraph);
161 return pPara->member.para.nCharOfs + pRun->member.run.nCharOfs + nOfs;
162}
163
164/******************************************************************************
165 * ME_CursorFromCharOfs
166 *
167 * Converts a character offset (relative to the start of the document) to
168 * a cursor structure (which contains a run and a position relative to that
169 * run).
170 */
171void ME_CursorFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_Cursor *pCursor)
172{
173 ME_RunOfsFromCharOfs(editor, nCharOfs, &pCursor->pPara,
174 &pCursor->pRun, &pCursor->nOffset);
175}
176
177/******************************************************************************
178 * ME_RunOfsFromCharOfs
179 *
180 * Find a run and relative character offset given an absolute character offset
181 * (absolute offset being an offset relative to the start of the document).
182 * Kind of a "global to local" offset conversion.
183 */
185 int nCharOfs,
186 ME_DisplayItem **ppPara,
187 ME_DisplayItem **ppRun,
188 int *pOfs)
189{
190 ME_DisplayItem *item, *next_item;
191 int endOfs = nCharOfs, len = ME_GetTextLength(editor);
192
193 nCharOfs = max(nCharOfs, 0);
194 nCharOfs = min(nCharOfs, len);
195
196 /* Find the paragraph at the offset. */
197 next_item = editor->pBuffer->pFirst->member.para.next_para;
198 do {
199 item = next_item;
200 next_item = item->member.para.next_para;
201 } while (next_item->member.para.nCharOfs <= nCharOfs);
202 assert(item->type == diParagraph);
203 nCharOfs -= item->member.para.nCharOfs;
204 if (ppPara) *ppPara = item;
205
206 /* Find the run at the offset. */
207 next_item = ME_FindItemFwd(item, diRun);
208 do {
209 item = next_item;
211 } while (next_item->type == diRun &&
212 next_item->member.run.nCharOfs <= nCharOfs);
213 assert(item->type == diRun);
214 nCharOfs -= item->member.run.nCharOfs;
215
216 if (ppRun) *ppRun = item;
217 if (pOfs) {
218 if (((*ppRun)->member.run.nFlags & MERF_ENDPARA) && endOfs > len)
219 *pOfs = (*ppRun)->member.run.len;
220 else *pOfs = nCharOfs;
221 }
222}
223
224/******************************************************************************
225 * ME_JoinRuns
226 *
227 * Merges two adjacent runs, the one given as a parameter and the next one.
228 */
230{
231 ME_DisplayItem *pNext = p->next;
232 int i;
233 assert(p->type == diRun && pNext->type == diRun);
234 assert(p->member.run.nCharOfs != -1);
236
237 /* Update all cursors so that they don't contain the soon deleted run */
238 for (i=0; i<editor->nCursors; i++) {
239 if (editor->pCursors[i].pRun == pNext) {
240 editor->pCursors[i].pRun = p;
241 editor->pCursors[i].nOffset += p->member.run.len;
242 }
243 }
244
245 p->member.run.len += pNext->member.run.len;
246 ME_Remove(pNext);
248 ME_UpdateRunFlags(editor, &p->member.run);
249 ME_CheckCharOffsets(editor);
250}
251
252/******************************************************************************
253 * ME_SplitRunSimple
254 *
255 * Does the most basic job of splitting a run into two - it does not
256 * update the positions and extents.
257 */
259{
260 ME_DisplayItem *run = cursor->pRun;
261 ME_DisplayItem *new_run;
262 int i;
263 int nOffset = cursor->nOffset;
264
266
267 new_run = ME_MakeRun(run->member.run.style,
269 new_run->member.run.nCharOfs = run->member.run.nCharOfs + nOffset;
270 new_run->member.run.len = run->member.run.len - nOffset;
271 new_run->member.run.para = run->member.run.para;
272 run->member.run.len = nOffset;
273 cursor->pRun = new_run;
274 cursor->nOffset = 0;
275
276 ME_InsertBefore(run->next, new_run);
277
278 ME_UpdateRunFlags(editor, &run->member.run);
279 ME_UpdateRunFlags(editor, &new_run->member.run);
280 for (i = 0; i < editor->nCursors; i++) {
281 if (editor->pCursors[i].pRun == run &&
282 editor->pCursors[i].nOffset >= nOffset) {
283 editor->pCursors[i].pRun = new_run;
284 editor->pCursors[i].nOffset -= nOffset;
285 }
286 }
287 mark_para_rewrap(editor, cursor->pPara);
288 return run;
289}
290
291/******************************************************************************
292 * ME_MakeRun
293 *
294 * A helper function to create run structures quickly.
295 */
297{
299 item->member.run.style = s;
300 item->member.run.reobj = NULL;
301 item->member.run.nFlags = nFlags;
302 item->member.run.nCharOfs = -1;
303 item->member.run.len = 0;
304 item->member.run.para = NULL;
305 item->member.run.num_glyphs = 0;
306 item->member.run.max_glyphs = 0;
307 item->member.run.glyphs = NULL;
308 item->member.run.vis_attrs = NULL;
309 item->member.run.advances = NULL;
310 item->member.run.offsets = NULL;
311 item->member.run.max_clusters = 0;
312 item->member.run.clusters = NULL;
314 return item;
315}
316
317/******************************************************************************
318 * ME_InsertRunAtCursor
319 *
320 * Inserts a new run with given style, flags and content at a given position,
321 * which is passed as a cursor structure (which consists of a run and
322 * a run-relative character offset).
323 */
326 const WCHAR *str, int len, int flags)
327{
328 ME_DisplayItem *pDI, *insert_before = cursor->pRun, *prev;
329
330 if (cursor->nOffset)
331 {
332 if (cursor->nOffset == cursor->pRun->member.run.len)
333 {
334 insert_before = ME_FindItemFwd( cursor->pRun, diRun );
335 if (!insert_before) insert_before = cursor->pRun; /* Always insert before the final eop run */
336 }
337 else
338 {
339 ME_SplitRunSimple( editor, cursor );
340 insert_before = cursor->pRun;
341 }
342 }
343
344 add_undo_delete_run( editor, insert_before->member.run.para->nCharOfs +
345 insert_before->member.run.nCharOfs, len );
346
347 pDI = ME_MakeRun(style, flags);
348 pDI->member.run.nCharOfs = insert_before->member.run.nCharOfs;
349 pDI->member.run.len = len;
350 pDI->member.run.para = insert_before->member.run.para;
351 ME_InsertString( pDI->member.run.para->text, pDI->member.run.nCharOfs, str, len );
352 ME_InsertBefore( insert_before, pDI );
353 TRACE("Shift length:%d\n", len);
354 ME_PropagateCharOffset( insert_before, len );
355 mark_para_rewrap(editor, get_di_from_para(insert_before->member.run.para));
356
357 /* Move any cursors that were at the end of the previous run to the end of the inserted run */
358 prev = ME_FindItemBack( pDI, diRun );
359 if (prev)
360 {
361 int i;
362
363 for (i = 0; i < editor->nCursors; i++)
364 {
365 if (editor->pCursors[i].pRun == prev &&
366 editor->pCursors[i].nOffset == prev->member.run.len)
367 {
368 editor->pCursors[i].pRun = pDI;
369 editor->pCursors[i].nOffset = len;
370 }
371 }
372 }
373
374 return pDI;
375}
376
377static BOOL run_is_splittable( const ME_Run *run )
378{
379 WCHAR *str = get_text( run, 0 ), *p;
380 int i;
381 BOOL found_ink = FALSE;
382
383 for (i = 0, p = str; i < run->len; i++, p++)
384 {
385 if (ME_IsWSpace( *p ))
386 {
387 if (found_ink) return TRUE;
388 }
389 else
390 found_ink = TRUE;
391 }
392 return FALSE;
393}
394
395static BOOL run_is_entirely_ws( const ME_Run *run )
396{
397 WCHAR *str = get_text( run, 0 ), *p;
398 int i;
399
400 for (i = 0, p = str; i < run->len; i++, p++)
401 if (!ME_IsWSpace( *p )) return FALSE;
402
403 return TRUE;
404}
405
406/******************************************************************************
407 * ME_UpdateRunFlags
408 *
409 * Determine some of run attributes given its content (style, text content).
410 * Some flags cannot be determined by this function (MERF_GRAPHICS,
411 * MERF_ENDPARA)
412 */
414{
415 assert(run->nCharOfs >= 0);
416
417 if (RUN_IS_HIDDEN(run) || run->nFlags & MERF_TABLESTART)
418 run->nFlags |= MERF_HIDDEN;
419 else
420 run->nFlags &= ~MERF_HIDDEN;
421
422 if (run_is_splittable( run ))
423 run->nFlags |= MERF_SPLITTABLE;
424 else
425 run->nFlags &= ~MERF_SPLITTABLE;
426
427 if (!(run->nFlags & MERF_NOTEXT))
428 {
429 if (run_is_entirely_ws( run ))
431 else
432 {
433 run->nFlags &= ~MERF_WHITESPACE;
434
435 if (ME_IsWSpace( *get_text( run, 0 ) ))
436 run->nFlags |= MERF_STARTWHITE;
437 else
438 run->nFlags &= ~MERF_STARTWHITE;
439
440 if (ME_IsWSpace( *get_text( run, run->len - 1 ) ))
441 run->nFlags |= MERF_ENDWHITE;
442 else
443 run->nFlags &= ~MERF_ENDWHITE;
444 }
445 }
446 else
448}
449
450/******************************************************************************
451 * ME_CharFromPointContext
452 *
453 * Returns a character position inside the run given a run-relative
454 * pixel horizontal position.
455 *
456 * If closest is FALSE return the actual character
457 * If closest is TRUE will round to the closest leading edge.
458 * ie. if the second character is at pixel position 8 and third at 16 then for:
459 * closest = FALSE cx = 0..7 return 0, cx = 8..15 return 1
460 * closest = TRUE cx = 0..3 return 0, cx = 4..11 return 1.
461 */
462int ME_CharFromPointContext(ME_Context *c, int cx, ME_Run *run, BOOL closest, BOOL visual_order)
463{
464 ME_String *mask_text = NULL;
465 WCHAR *str;
466 int fit = 0;
467 SIZE sz, sz2, sz3;
468 if (!run->len || cx <= 0)
469 return 0;
470
471 if (run->nFlags & (MERF_TAB | MERF_ENDCELL))
472 {
473 if (!closest || cx < run->nWidth / 2) return 0;
474 return 1;
475 }
476
477 if (run->nFlags & MERF_GRAPHICS)
478 {
479 SIZE sz;
480 ME_GetOLEObjectSize(c, run, &sz);
481 if (!closest || cx < sz.cx / 2) return 0;
482 return 1;
483 }
484
485 if (run->para->nFlags & MEPF_COMPLEX)
486 {
487 int cp, trailing;
488 if (visual_order && run->script_analysis.fRTL) cx = run->nWidth - cx - 1;
489
490 ScriptXtoCP( cx, run->len, run->num_glyphs, run->clusters, run->vis_attrs, run->advances, &run->script_analysis,
491 &cp, &trailing );
492 TRACE("x %d cp %d trailing %d (run width %d) rtl %d log order %d\n", cx, cp, trailing, run->nWidth,
494 return closest ? cp + trailing : cp;
495 }
496
497 if (c->editor->cPasswordMask)
498 {
499 mask_text = ME_MakeStringR( c->editor->cPasswordMask, run->len );
500 str = mask_text->szData;
501 }
502 else
503 str = get_text( run, 0 );
504
505 select_style(c, run->style);
506 GetTextExtentExPointW(c->hDC, str, run->len,
507 cx, &fit, NULL, &sz);
508 if (closest && fit != run->len)
509 {
510 GetTextExtentPoint32W(c->hDC, str, fit, &sz2);
511 GetTextExtentPoint32W(c->hDC, str, fit + 1, &sz3);
512 if (cx >= (sz2.cx+sz3.cx)/2)
513 fit = fit + 1;
514 }
515
516 ME_DestroyString( mask_text );
517
518 return fit;
519}
520
521int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run, BOOL closest, BOOL visual_order)
522{
524 int ret;
525
526 ME_InitContext( &c, editor, ITextHost_TxGetDC( editor->texthost ) );
527 ret = ME_CharFromPointContext( &c, cx, run, closest, visual_order );
529 return ret;
530}
531
532/******************************************************************************
533 * ME_GetTextExtent
534 *
535 * Finds a width and a height of the text using a specified style
536 */
537static void ME_GetTextExtent(ME_Context *c, LPCWSTR szText, int nChars, ME_Style *s, SIZE *size)
538{
539 if (c->hDC)
540 {
541 select_style( c, s );
542 GetTextExtentPoint32W( c->hDC, szText, nChars, size );
543 }
544 else
545 {
546 size->cx = 0;
547 size->cy = 0;
548 }
549}
550
551/******************************************************************************
552 * ME_PointFromCharContext
553 *
554 * Returns a run-relative pixel position given a run-relative character
555 * position (character offset)
556 */
557int ME_PointFromCharContext(ME_Context *c, ME_Run *pRun, int nOffset, BOOL visual_order)
558{
559 SIZE size;
560 ME_String *mask_text = NULL;
561 WCHAR *str;
562
563 if (pRun->nFlags & MERF_GRAPHICS)
564 {
565 if (nOffset)
566 ME_GetOLEObjectSize(c, pRun, &size);
567 return nOffset != 0;
568 } else if (pRun->nFlags & MERF_ENDPARA) {
569 nOffset = 0;
570 }
571
572 if (pRun->para->nFlags & MEPF_COMPLEX)
573 {
574 int x;
575 ScriptCPtoX( nOffset, FALSE, pRun->len, pRun->num_glyphs, pRun->clusters,
576 pRun->vis_attrs, pRun->advances, &pRun->script_analysis, &x );
577 if (visual_order && pRun->script_analysis.fRTL) x = pRun->nWidth - x - 1;
578 return x;
579 }
580 if (c->editor->cPasswordMask)
581 {
582 mask_text = ME_MakeStringR(c->editor->cPasswordMask, pRun->len);
583 str = mask_text->szData;
584 }
585 else
586 str = get_text( pRun, 0 );
587
588 ME_GetTextExtent(c, str, nOffset, pRun->style, &size);
589 ME_DestroyString( mask_text );
590 return size.cx;
591}
592
593/******************************************************************************
594 * ME_PointFromChar
595 *
596 * Calls ME_PointFromCharContext after first creating a context.
597 */
598int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset, BOOL visual_order)
599{
601 int ret;
602
603 ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost));
604 ret = ME_PointFromCharContext( &c, pRun, nOffset, visual_order );
606
607 return ret;
608}
609
610/******************************************************************************
611 * ME_GetRunSizeCommon
612 *
613 * Finds width, height, ascent and descent of a run, up to given character
614 * (nLen).
615 */
617 int startx, int *pAscent, int *pDescent)
618{
619 static const WCHAR spaceW[] = {' ',0};
620 SIZE size;
621
622 nLen = min( nLen, run->len );
623
624 if (run->nFlags & MERF_ENDPARA)
625 {
626 nLen = min( nLen, 1 );
627 ME_GetTextExtent(c, spaceW, nLen, run->style, &size);
628 }
629 else if (para->nFlags & MEPF_COMPLEX)
630 {
631 size.cx = run->nWidth;
632 }
633 else if (c->editor->cPasswordMask)
634 {
635 ME_String *szMasked = ME_MakeStringR(c->editor->cPasswordMask,nLen);
636 ME_GetTextExtent(c, szMasked->szData, nLen,run->style, &size);
637 ME_DestroyString(szMasked);
638 }
639 else
640 {
641 ME_GetTextExtent(c, get_text( run, 0 ), nLen, run->style, &size);
642 }
643 *pAscent = run->style->tm.tmAscent;
644 *pDescent = run->style->tm.tmDescent;
645 size.cy = *pAscent + *pDescent;
646
647 if (run->nFlags & MERF_TAB)
648 {
649 int pos = 0, i = 0, ppos, shift = 0;
650 const PARAFORMAT2 *pFmt = &para->fmt;
651
652 if (c->editor->bEmulateVersion10 && /* v1.0 - 3.0 */
653 pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE)
654 /* The horizontal gap shifts the tab positions to leave the gap. */
655 shift = pFmt->dxOffset * 2;
656 do {
657 if (i < pFmt->cTabCount)
658 {
659 /* Only one side of the horizontal gap is needed at the end of
660 * the table row. */
661 if (i == pFmt->cTabCount -1)
662 shift = shift >> 1;
663 pos = shift + (pFmt->rgxTabs[i]&0x00FFFFFF);
664 i++;
665 }
666 else
667 {
669 }
670 ppos = ME_twips2pointsX(c, pos);
671 if (ppos > startx + run->pt.x) {
672 size.cx = ppos - startx - run->pt.x;
673 break;
674 }
675 } while(1);
676 size.cy = *pAscent + *pDescent;
677 return size;
678 }
679 if (run->nFlags & MERF_GRAPHICS)
680 {
681 ME_GetOLEObjectSize(c, run, &size);
682 if (size.cy > *pAscent)
683 *pAscent = size.cy;
684 /* descent is unchanged */
685 return size;
686 }
687 return size;
688}
689
690/******************************************************************************
691 * ME_SetSelectionCharFormat
692 *
693 * Applies a style change, either to a current selection, or to insert cursor
694 * (ie. the style next typed characters will use).
695 */
697{
698 if (!ME_IsSelection(editor))
699 {
700 ME_Style *s;
701 if (!editor->pBuffer->pCharStyle)
702 editor->pBuffer->pCharStyle = ME_GetInsertStyle(editor, 0);
703 s = ME_ApplyStyle(editor, editor->pBuffer->pCharStyle, pFmt);
705 editor->pBuffer->pCharStyle = s;
706 } else {
707 ME_Cursor *from, *to;
708 ME_GetSelection(editor, &from, &to);
709 ME_SetCharFormat(editor, from, to, pFmt);
710 }
711}
712
713/******************************************************************************
714 * ME_SetCharFormat
715 *
716 * Applies a style change to the specified part of the text
717 *
718 * The start and end cursors specify the part of the text. These cursors will
719 * be updated to stay valid, but this function may invalidate other
720 * non-selection cursors. The end cursor may be NULL to specify all the text
721 * following the start cursor.
722 *
723 * If no text is selected, then nothing is done.
724 */
726{
727 ME_DisplayItem *run, *start_run = start->pRun, *end_run = NULL;
728
729 if (end && start->pRun == end->pRun && start->nOffset == end->nOffset)
730 return;
731
732 if (start->nOffset == start->pRun->member.run.len)
733 start_run = ME_FindItemFwd( start->pRun, diRun );
734 else if (start->nOffset)
735 {
736 /* SplitRunSimple may or may not update the cursors, depending on whether they
737 * are selection cursors, but we need to make sure they are valid. */
738 int split_offset = start->nOffset;
739 ME_DisplayItem *split_run = ME_SplitRunSimple(editor, start);
740 start_run = start->pRun;
741 if (end && end->pRun == split_run)
742 {
743 end->pRun = start->pRun;
744 end->nOffset -= split_offset;
745 }
746 }
747
748 if (end)
749 {
750 if (end->nOffset == end->pRun->member.run.len)
751 end_run = ME_FindItemFwd( end->pRun, diRun );
752 else
753 {
754 if (end->nOffset) ME_SplitRunSimple(editor, end);
755 end_run = end->pRun;
756 }
757 }
758
759 for (run = start_run; run != end_run; run = ME_FindItemFwd( run, diRun ))
760 {
761 ME_Style *new_style = ME_ApplyStyle(editor, run->member.run.style, pFmt);
762 ME_Paragraph *para = run->member.run.para;
763
764 add_undo_set_char_fmt( editor, run->member.run.para->nCharOfs + run->member.run.nCharOfs,
765 run->member.run.len, &run->member.run.style->fmt );
767 run->member.run.style = new_style;
768
769 /* The para numbering style depends on the eop style */
770 if ((run->member.run.nFlags & MERF_ENDPARA) && para->para_num.style)
771 {
772 ME_ReleaseStyle(para->para_num.style);
773 para->para_num.style = NULL;
774 }
775 mark_para_rewrap(editor, get_di_from_para(para));
776 }
777}
778
780{
781 ME_CopyCharFormat(pFmt, &run->member.run.style->fmt);
782}
783
784/******************************************************************************
785 * ME_GetDefaultCharFormat
786 *
787 * Retrieves the current default character style (the one applied where no
788 * other style was applied) .
789 */
791{
792 ME_CopyCharFormat(pFmt, &editor->pBuffer->pDefaultStyle->fmt);
793}
794
795/******************************************************************************
796 * ME_GetSelectionCharFormat
797 *
798 * If selection exists, it returns all style elements that are set consistently
799 * in the whole selection. If not, it just returns the current style.
800 */
802{
803 ME_Cursor *from, *to;
804 if (!ME_IsSelection(editor) && editor->pBuffer->pCharStyle)
805 {
806 ME_CopyCharFormat(pFmt, &editor->pBuffer->pCharStyle->fmt);
807 return;
808 }
809 ME_GetSelection(editor, &from, &to);
810 ME_GetCharFormat(editor, from, to, pFmt);
811}
812
813/******************************************************************************
814 * ME_GetCharFormat
815 *
816 * Returns the style consisting of those attributes which are consistently set
817 * in the whole character range.
818 */
820 const ME_Cursor *to, CHARFORMAT2W *pFmt)
821{
822 ME_DisplayItem *run, *run_end;
823 CHARFORMAT2W tmp;
824
825 run = from->pRun;
826 /* special case - if selection is empty, take previous char's formatting */
827 if (from->pRun == to->pRun && from->nOffset == to->nOffset)
828 {
829 if (!from->nOffset)
830 {
832 if (tmp_run->type == diRun) {
833 ME_GetRunCharFormat(editor, tmp_run, pFmt);
834 return;
835 }
836 }
837 ME_GetRunCharFormat(editor, run, pFmt);
838 return;
839 }
840
841 run_end = to->pRun;
842 if (!to->nOffset)
843 run_end = ME_FindItemBack(run_end, diRun);
844
845 ME_GetRunCharFormat(editor, run, pFmt);
846
847 if (run == run_end) return;
848
849 do {
850 /* FIXME add more style feature comparisons */
853
854 run = ME_FindItemFwd(run, diRun);
855
856 ZeroMemory(&tmp, sizeof(tmp));
857 tmp.cbSize = sizeof(tmp);
858 ME_GetRunCharFormat(editor, run, &tmp);
859
860 assert((tmp.dwMask & dwAttribs) == dwAttribs);
861 /* reset flags that differ */
862
863 if (pFmt->yHeight != tmp.yHeight)
864 pFmt->dwMask &= ~CFM_SIZE;
865 if (pFmt->dwMask & CFM_FACE)
866 {
867 if (!(tmp.dwMask & CFM_FACE))
868 pFmt->dwMask &= ~CFM_FACE;
869 else if (wcscmp(pFmt->szFaceName, tmp.szFaceName) ||
870 pFmt->bPitchAndFamily != tmp.bPitchAndFamily)
871 pFmt->dwMask &= ~CFM_FACE;
872 }
873 if (pFmt->yHeight != tmp.yHeight)
874 pFmt->dwMask &= ~CFM_SIZE;
875 if (pFmt->bUnderlineType != tmp.bUnderlineType)
876 pFmt->dwMask &= ~CFM_UNDERLINETYPE;
877 if (pFmt->dwMask & CFM_COLOR)
878 {
879 if (!((pFmt->dwEffects&CFE_AUTOCOLOR) & (tmp.dwEffects&CFE_AUTOCOLOR)))
880 {
881 if (pFmt->crTextColor != tmp.crTextColor)
882 pFmt->dwMask &= ~CFM_COLOR;
883 }
884 }
885
886 pFmt->dwMask &= ~((pFmt->dwEffects ^ tmp.dwEffects) & dwEffects);
887 pFmt->dwEffects = tmp.dwEffects;
888
889 } while(run != run_end);
890}
Arabic default style
Definition: afstyles.h:94
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define TRACE_(x)
Definition: compat.h:76
#define TRACE_ON(x)
Definition: compat.h:75
#define WINE_DECLARE_DEBUG_CHANNEL(x)
Definition: compat.h:45
BOOL ME_IsSelection(ME_TextEditor *editor)
Definition: caret.c:1578
int ME_GetSelection(ME_TextEditor *editor, ME_Cursor **from, ME_Cursor **to)
Definition: caret.c:57
int ME_GetTextLength(ME_TextEditor *editor)
Definition: caret.c:83
void ME_DestroyContext(ME_Context *c)
Definition: context.c:44
void ME_InitContext(ME_Context *c, ME_TextEditor *editor, HDC hDC)
Definition: context.c:23
void ME_CursorFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_Cursor *pCursor)
Definition: run.c:171
void ME_SkipAndPropagateCharOffset(ME_DisplayItem *p, int shift)
Definition: run.c:46
int ME_PointFromCharContext(ME_Context *c, ME_Run *pRun, int nOffset, BOOL visual_order)
Definition: run.c:557
static void ME_GetTextExtent(ME_Context *c, LPCWSTR szText, int nChars, ME_Style *s, SIZE *size)
Definition: run.c:537
int ME_CharFromPointContext(ME_Context *c, int cx, ME_Run *run, BOOL closest, BOOL visual_order)
Definition: run.c:462
ME_DisplayItem * ME_InsertRunAtCursor(ME_TextEditor *editor, ME_Cursor *cursor, ME_Style *style, const WCHAR *str, int len, int flags)
Definition: run.c:325
void ME_SetCharFormat(ME_TextEditor *editor, ME_Cursor *start, ME_Cursor *end, CHARFORMAT2W *pFmt)
Definition: run.c:725
static BOOL run_is_splittable(const ME_Run *run)
Definition: run.c:377
ME_DisplayItem * ME_SplitRunSimple(ME_TextEditor *editor, ME_Cursor *cursor)
Definition: run.c:258
void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **ppPara, ME_DisplayItem **ppRun, int *pOfs)
Definition: run.c:184
void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run)
Definition: run.c:413
void ME_GetCharFormat(ME_TextEditor *editor, const ME_Cursor *from, const ME_Cursor *to, CHARFORMAT2W *pFmt)
Definition: run.c:819
void ME_PropagateCharOffset(ME_DisplayItem *p, int shift)
Definition: run.c:59
static void ME_GetRunCharFormat(ME_TextEditor *editor, ME_DisplayItem *run, CHARFORMAT2W *pFmt)
Definition: run.c:779
static BOOL run_is_entirely_ws(const ME_Run *run)
Definition: run.c:395
int ME_CharOfsFromRunOfs(ME_TextEditor *editor, const ME_DisplayItem *pPara, const ME_DisplayItem *pRun, int nOfs)
Definition: run.c:156
int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset, BOOL visual_order)
Definition: run.c:598
ME_DisplayItem * ME_MakeRun(ME_Style *s, int nFlags)
Definition: run.c:296
SIZE ME_GetRunSizeCommon(ME_Context *c, const ME_Paragraph *para, ME_Run *run, int nLen, int startx, int *pAscent, int *pDescent)
Definition: run.c:616
BOOL ME_CanJoinRuns(const ME_Run *run1, const ME_Run *run2)
Definition: run.c:35
void ME_JoinRuns(ME_TextEditor *editor, ME_DisplayItem *p)
Definition: run.c:229
void ME_SetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
Definition: run.c:696
void ME_GetSelectionCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
Definition: run.c:801
void ME_CheckCharOffsets(ME_TextEditor *editor)
Definition: run.c:101
int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run, BOOL closest, BOOL visual_order)
Definition: run.c:521
void ME_GetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *pFmt)
Definition: run.c:790
HRESULT WINAPI ScriptXtoCP(int iX, int cChars, int cGlyphs, const WORD *pwLogClust, const SCRIPT_VISATTR *psva, const int *piAdvance, const SCRIPT_ANALYSIS *psa, int *piCP, int *piTrailing)
Definition: usp10.c:2854
HRESULT WINAPI ScriptCPtoX(int iCP, BOOL fTrailing, int cChars, int cGlyphs, const WORD *pwLogClust, const SCRIPT_VISATTR *psva, const int *piAdvance, const SCRIPT_ANALYSIS *psa, int *piX)
Definition: usp10.c:2650
#define assert(x)
Definition: debug.h:53
void ME_ReleaseStyle(ME_Style *item) DECLSPEC_HIDDEN
Definition: style.c:462
ME_Style * ME_GetInsertStyle(ME_TextEditor *editor, int nCursor) DECLSPEC_HIDDEN
Definition: style.c:476
void ME_AddRefStyle(ME_Style *item) DECLSPEC_HIDDEN
Definition: style.c:454
BOOL add_undo_set_char_fmt(ME_TextEditor *, int pos, int len, const CHARFORMAT2W *fmt) DECLSPEC_HIDDEN
Definition: undo.c:164
void mark_para_rewrap(ME_TextEditor *editor, ME_DisplayItem *para) DECLSPEC_HIDDEN
Definition: para.c:26
ME_Style * ME_ApplyStyle(ME_TextEditor *ed, ME_Style *sSrc, CHARFORMAT2W *style) DECLSPEC_HIDDEN
Definition: style.c:156
void ME_GetOLEObjectSize(const ME_Context *c, ME_Run *run, SIZE *pSize) DECLSPEC_HIDDEN
Definition: richole.c:5727
void ME_DestroyDisplayItem(ME_DisplayItem *item) DECLSPEC_HIDDEN
Definition: list.c:160
int ME_twips2pointsX(const ME_Context *c, int x) DECLSPEC_HIDDEN
Definition: paint.c:153
ME_DisplayItem * ME_FindItemBack(ME_DisplayItem *di, ME_DIType nTypeOrClass) DECLSPEC_HIDDEN
Definition: list.c:111
void select_style(ME_Context *c, ME_Style *s) DECLSPEC_HIDDEN
Definition: style.c:369
ME_DisplayItem * ME_GetParagraph(ME_DisplayItem *run) DECLSPEC_HIDDEN
Definition: para.c:815
void ME_DumpDocument(ME_TextBuffer *buffer) DECLSPEC_HIDDEN
Definition: list.c:187
#define ITextHost_TxGetDC(This)
Definition: editor.h:287
static int ME_IsWSpace(WCHAR ch)
Definition: editor.h:101
BOOL add_undo_delete_run(ME_TextEditor *, int pos, int len) DECLSPEC_HIDDEN
Definition: undo.c:204
void ME_Remove(ME_DisplayItem *diWhere) DECLSPEC_HIDDEN
Definition: list.c:35
ME_DisplayItem * get_di_from_para(ME_Paragraph *para) DECLSPEC_HIDDEN
Definition: para.c:32
void ME_InsertBefore(ME_DisplayItem *diWhere, ME_DisplayItem *diWhat) DECLSPEC_HIDDEN
Definition: list.c:26
#define RUN_IS_HIDDEN(run)
Definition: editor.h:29
void ME_CopyCharFormat(CHARFORMAT2W *pDest, const CHARFORMAT2W *pSrc) DECLSPEC_HIDDEN
Definition: style.c:230
void ME_DestroyString(ME_String *s) DECLSPEC_HIDDEN
Definition: string.c:96
ME_DisplayItem * ME_MakeDI(ME_DIType type) DECLSPEC_HIDDEN
Definition: list.c:178
static WCHAR * get_text(const ME_Run *run, int offset)
Definition: editor.h:41
ME_DisplayItem * ME_FindItemFwd(ME_DisplayItem *di, ME_DIType nTypeOrClass) DECLSPEC_HIDDEN
Definition: list.c:134
BOOL ME_InsertString(ME_String *s, int ofs, const WCHAR *insert, int len) DECLSPEC_HIDDEN
Definition: string.c:103
static const char * debugstr_run(const ME_Run *run)
Definition: editor.h:46
ME_String * ME_MakeStringR(WCHAR cRepeat, int nMaxChars) DECLSPEC_HIDDEN
Definition: string.c:85
#define MERF_STARTWHITE
Definition: editstr.h:116
#define MERF_TAB
Definition: editstr.h:107
#define MERF_NOTEXT
Definition: editstr.h:133
#define MERF_ENDPARA
Definition: editstr.h:122
#define MERF_NONTEXT
Definition: editstr.h:111
#define MERF_ENDWHITE
Definition: editstr.h:118
#define MERF_HIDDEN
Definition: editstr.h:126
#define MERF_ENDCELL
Definition: editstr.h:109
#define MERF_GRAPHICS
Definition: editstr.h:105
#define MEPF_COMPLEX
Definition: editstr.h:146
@ diTextEnd
Definition: editstr.h:89
@ diRunOrParagraphOrEnd
Definition: editstr.h:97
@ diCell
Definition: editstr.h:86
@ diRun
Definition: editstr.h:87
@ diRunOrParagraph
Definition: editstr.h:94
@ diParagraph
Definition: editstr.h:85
#define MERF_SPLITTABLE
Definition: editstr.h:114
#define MERF_STYLEFLAGS
Definition: editstr.h:103
#define MERF_TABLESTART
Definition: editstr.h:128
#define MERF_SPLITMASK
Definition: editstr.h:136
#define MERF_WHITESPACE
Definition: editstr.h:120
#define MERF_NOJOIN
Definition: editstr.h:131
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint start
Definition: gl.h:1545
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLdouble s
Definition: gl.h:2039
GLuint GLuint end
Definition: gl.h:1545
GLsizeiptr size
Definition: glext.h:5919
const GLubyte * c
Definition: glext.h:8905
GLbitfield flags
Definition: glext.h:7161
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLsizei len
Definition: glext.h:6722
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
const char cursor[]
Definition: icontest.c:13
#define c
Definition: ke_i.h:80
POINT cp
Definition: magnifier.c:59
static ATOM item
Definition: dde.c:856
#define shift
Definition: input.c:1755
#define min(a, b)
Definition: monoChain.cc:55
static const WCHAR spaceW[]
Definition: mxwriter.c:44
_Out_opt_ int * cx
Definition: commctrl.h:585
#define CFM_PROTECTED
Definition: richedit.h:336
#define CFM_STRIKEOUT
Definition: richedit.h:335
#define CFE_AUTOCOLOR
Definition: richedit.h:414
#define PFM_TABLE
Definition: richedit.h:870
#define CFM_ITALIC
Definition: richedit.h:333
#define lDefaultTab
Definition: richedit.h:215
#define CFM_LINK
Definition: richedit.h:337
#define CFM_SIZE
Definition: richedit.h:362
#define PFE_TABLE
Definition: richedit.h:944
#define CFM_BOLD
Definition: richedit.h:332
#define CFM_UNDERLINETYPE
Definition: richedit.h:355
#define CFM_FACE
Definition: richedit.h:360
#define CFM_UNDERLINE
Definition: richedit.h:334
#define CFM_COLOR
Definition: richedit.h:361
#define CFM_SUPERSCRIPT
Definition: richedit.h:349
const WCHAR * str
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define TRACE(s)
Definition: solgame.cpp:4
CardRegion * from
Definition: spigame.cpp:19
LONG cx
Definition: kdterminal.h:27
DWORD dwMask
Definition: richedit.h:306
WCHAR szFaceName[LF_FACESIZE]
Definition: richedit.h:313
DWORD dwEffects
Definition: richedit.h:307
BYTE bUnderlineType
Definition: richedit.h:321
LONG yHeight
Definition: richedit.h:308
COLORREF crTextColor
Definition: richedit.h:310
BYTE bPitchAndFamily
Definition: richedit.h:312
DWORD dwMask
Definition: richedit.h:667
LONG dxOffset
Definition: richedit.h:672
LONG rgxTabs[MAX_TAB_STOPS]
Definition: richedit.h:675
SHORT cTabCount
Definition: richedit.h:674
WORD wEffects
Definition: richedit.h:669
ME_DisplayItem * pPara
Definition: editstr.h:275
int nOffset
Definition: editstr.h:277
ME_DisplayItem * pRun
Definition: editstr.h:276
union tagME_DisplayItem::@536 member
ME_DIType type
Definition: editstr.h:256
struct tagME_DisplayItem * next
Definition: editstr.h:257
ME_Paragraph para
Definition: editstr.h:262
struct tagME_DisplayItem * next_para
Definition: editstr.h:217
struct para_num para_num
Definition: editstr.h:215
PARAFORMAT2 fmt
Definition: editstr.h:204
int num_glyphs
Definition: editstr.h:171
POINT pt
Definition: editstr.h:167
int nCharOfs
Definition: editstr.h:162
SCRIPT_VISATTR * vis_attrs
Definition: editstr.h:173
struct tagME_Paragraph * para
Definition: editstr.h:161
int * advances
Definition: editstr.h:174
ME_Style * style
Definition: editstr.h:160
SCRIPT_ANALYSIS script_analysis
Definition: editstr.h:170
int nWidth
Definition: editstr.h:164
int nFlags
Definition: editstr.h:165
int len
Definition: editstr.h:163
WORD * clusters
Definition: editstr.h:177
WCHAR * szData
Definition: editstr.h:56
CHARFORMAT2W fmt
Definition: editstr.h:73
TEXTMETRICW tm
Definition: editstr.h:76
ME_DisplayItem * pFirst
Definition: editstr.h:268
ME_Style * pDefaultStyle
Definition: editstr.h:270
ME_Style * pCharStyle
Definition: editstr.h:269
ITextHost * texthost
Definition: editstr.h:383
ME_Cursor * pCursors
Definition: editstr.h:387
ME_TextBuffer * pBuffer
Definition: editstr.h:386
long x
Definition: polytest.cpp:48
LONG tmAscent
Definition: wingdi.h:2384
LONG tmDescent
Definition: wingdi.h:2385
WORD fLogicalOrder
Definition: usp10.h:144
#define max(a, b)
Definition: svc.c:63
int ret
#define ZeroMemory
Definition: winbase.h:1712
BOOL WINAPI GetTextExtentExPointW(_In_ HDC hdc, _In_reads_(cchString) LPCWSTR lpszString, _In_ int cchString, _In_ int nMaxExtent, _Out_opt_ LPINT lpnFit, _Out_writes_to_opt_(cchString, *lpnFit) LPINT lpnDx, _Out_ LPSIZE lpSize)
BOOL WINAPI GetTextExtentPoint32W(_In_ HDC hdc, _In_reads_(c) LPCWSTR lpString, _In_ int c, _Out_ LPSIZE psizl)
__wchar_t WCHAR
Definition: xmlstorage.h:180
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185