ReactOS 0.4.16-dev-292-gbbdcc14
wrap.c
Go to the documentation of this file.
1/*
2 * RichEdit - Paragraph wrapping. Don't try to understand it. You've been
3 * warned !
4 *
5 * Copyright 2004 by Krzysztof Foltman
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22
23#include "editor.h"
24
26
27/*
28 * Unsolved problems:
29 *
30 * - center and right align in WordPad omits all spaces at the start, we don't
31 * - objects/images are not handled yet
32 * - no tabs
33 */
34
35typedef struct tagME_WrapContext
36{
40 int nFirstMargin; /* Offset to first line's text, always to the text itself even if a para number is present */
41 int nParaNumOffset; /* Offset to the para number */
42 int nAvailWidth; /* Width avail for text to wrap into. Does not include any para number text */
43 int nRow;
48
51
53{
54 heap_free( run->glyphs );
55 run->glyphs = heap_alloc( run->max_glyphs * (sizeof(WORD) + sizeof(SCRIPT_VISATTR) + sizeof(int) + sizeof(GOFFSET)) );
56 if (!run->glyphs) return FALSE;
57
58 run->vis_attrs = (SCRIPT_VISATTR*)((char*)run->glyphs + run->max_glyphs * sizeof(WORD));
59 run->advances = (int*)((char*)run->glyphs + run->max_glyphs * (sizeof(WORD) + sizeof(SCRIPT_VISATTR)));
60 run->offsets = (GOFFSET*)((char*)run->glyphs + run->max_glyphs * (sizeof(WORD) + sizeof(SCRIPT_VISATTR) + sizeof(int)));
61
62 return TRUE;
63}
64
66{
67 HRESULT hr;
68 int i;
69
70 if (!run->glyphs)
71 {
72 run->max_glyphs = 1.5 * run->len + 16; /* This is suggested in the uniscribe documentation */
73 run->max_glyphs = (run->max_glyphs + 7) & ~7; /* Keep alignment simple */
75 }
76
77 if (run->max_clusters < run->len)
78 {
79 heap_free( run->clusters );
80 run->max_clusters = run->len * 2;
81 run->clusters = heap_alloc( run->max_clusters * sizeof(WORD) );
82 }
83
84 select_style( c, run->style );
85 while (1)
86 {
87 hr = ScriptShape( c->hDC, &run->style->script_cache, get_text( run, 0 ), run->len, run->max_glyphs,
88 &run->script_analysis, run->glyphs, run->clusters, run->vis_attrs, &run->num_glyphs );
89 if (hr != E_OUTOFMEMORY) break;
90 if (run->max_glyphs > 10 * run->len) break; /* something has clearly gone wrong */
91 run->max_glyphs *= 2;
93 }
94
95 if (SUCCEEDED(hr))
96 hr = ScriptPlace( c->hDC, &run->style->script_cache, run->glyphs, run->num_glyphs, run->vis_attrs,
97 &run->script_analysis, run->advances, run->offsets, NULL );
98
99 if (SUCCEEDED(hr))
100 {
101 for (i = 0, run->nWidth = 0; i < run->num_glyphs; i++)
102 run->nWidth += run->advances[i];
103 }
104
105 return hr;
106}
107
108/******************************************************************************
109 * calc_run_extent
110 *
111 * Updates the size of the run (fills width, ascent and descent). The height
112 * is calculated based on whole row's ascent and descent anyway, so no need
113 * to use it here.
114 */
115static void calc_run_extent(ME_Context *c, const ME_Paragraph *para, int startx, ME_Run *run)
116{
117 if (run->nFlags & MERF_HIDDEN) run->nWidth = 0;
118 else
119 {
120 SIZE size = ME_GetRunSizeCommon( c, para, run, run->len, startx, &run->nAscent, &run->nDescent );
121 run->nWidth = size.cx;
122 }
123}
124
125/******************************************************************************
126 * split_run_extents
127 *
128 * Splits a run into two in a given place. It also updates the screen position
129 * and size (extent) of the newly generated runs.
130 */
132{
133 ME_TextEditor *editor = wc->context->editor;
134 ME_Run *run, *run2;
135 ME_Paragraph *para = &wc->pPara->member.para;
136 ME_Cursor cursor = {wc->pPara, item, nVChar};
137
138 assert(item->member.run.nCharOfs != -1);
139 ME_CheckCharOffsets(editor);
140
141 run = &item->member.run;
142
143 TRACE("Before split: %s(%d, %d)\n", debugstr_run( run ),
144 run->pt.x, run->pt.y);
145
146 ME_SplitRunSimple(editor, &cursor);
147
148 run2 = &cursor.pRun->member.run;
149 run2->script_analysis = run->script_analysis;
150
151 shape_run( wc->context, run );
152 shape_run( wc->context, run2 );
153 calc_run_extent(wc->context, para, wc->nRow ? wc->nLeftMargin : wc->nFirstMargin, run);
154
155 run2->pt.x = run->pt.x+run->nWidth;
156 run2->pt.y = run->pt.y;
157
158 ME_CheckCharOffsets(editor);
159
160 TRACE("After split: %s(%d, %d), %s(%d, %d)\n",
161 debugstr_run( run ), run->pt.x, run->pt.y,
162 debugstr_run( run2 ), run2->pt.x, run2->pt.y);
163
164 return cursor.pRun;
165}
166
167/******************************************************************************
168 * find_split_point
169 *
170 * Returns a character position to split inside the run given a run-relative
171 * pixel horizontal position. This version rounds left (ie. if the second
172 * character is at pixel position 8, then for cx=0..7 it returns 0).
173 */
174static int find_split_point( ME_Context *c, int cx, ME_Run *run )
175{
176 if (!run->len || cx <= 0) return 0;
177 return ME_CharFromPointContext( c, cx, run, FALSE, FALSE );
178}
179
180static ME_DisplayItem *ME_MakeRow(int height, int baseline, int width)
181{
183
184 item->member.row.nHeight = height;
185 item->member.row.nBaseline = baseline;
186 item->member.row.nWidth = width;
187 return item;
188}
189
191{
192 PARAFORMAT2 *pFmt;
193 ME_DisplayItem *para = wc->pPara;
194
195 pFmt = &para->member.para.fmt;
196 wc->pRowStart = NULL;
197 wc->bOverflown = FALSE;
199 wc->bWordWrap = wc->context->editor->bWordWrap;
201 wc->nAvailWidth = 0;
202 wc->bWordWrap = FALSE;
203 if (para->member.para.nFlags & MEPF_ROWEND)
204 {
205 ME_Cell *cell = &ME_FindItemBack(para, diCell)->member.cell;
206 cell->nWidth = 0;
207 }
208 } else if (para->member.para.pCell) {
209 ME_Cell *cell = &para->member.para.pCell->member.cell;
210 int width;
211
212 width = cell->nRightBoundary;
213 if (cell->prev_cell)
214 width -= cell->prev_cell->member.cell.nRightBoundary;
215 if (!cell->prev_cell)
216 {
217 int rowIndent = ME_GetTableRowEnd(para)->member.para.fmt.dxStartIndent;
218 width -= rowIndent;
219 }
220 cell->nWidth = max(ME_twips2pointsX(wc->context, width), 0);
221
222 wc->nAvailWidth = cell->nWidth
223 - (wc->nRow ? wc->nLeftMargin : wc->nFirstMargin) - wc->nRightMargin;
224 wc->bWordWrap = TRUE;
225 } else {
227 - (wc->nRow ? wc->nLeftMargin : wc->nFirstMargin) - wc->nRightMargin;
228 }
229 wc->pt.x = wc->context->pt.x;
230 if (wc->context->editor->bEmulateVersion10 && /* v1.0 - 3.0 */
231 pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE)
232 /* Shift the text down because of the border. */
233 wc->pt.y++;
234}
235
237{
239 int i, num_runs = 0;
240 int buf[16 * 5]; /* 5 arrays - 4 of int & 1 of BYTE, alloc space for 5 of ints */
241 int *vis_to_log = buf, *log_to_vis, *widths, *pos;
242 BYTE *levels;
243 BOOL found_black = FALSE;
244
245 for (p = end->prev; p != start->prev; p = p->prev)
246 {
247 if (p->type == diRun)
248 {
249 if (!found_black) found_black = !(p->member.run.nFlags & (MERF_WHITESPACE | MERF_ENDPARA));
250 if (found_black) num_runs++;
251 }
252 }
253
254 TRACE("%d runs\n", num_runs);
255 if (!num_runs) return;
256
257 if (num_runs > ARRAY_SIZE( buf ) / 5)
258 vis_to_log = heap_alloc( num_runs * sizeof(int) * 5 );
259
260 log_to_vis = vis_to_log + num_runs;
261 widths = vis_to_log + 2 * num_runs;
262 pos = vis_to_log + 3 * num_runs;
263 levels = (BYTE*)(vis_to_log + 4 * num_runs);
264
265 for (i = 0, p = start; i < num_runs; p = p->next)
266 {
267 if (p->type == diRun)
268 {
269 levels[i] = p->member.run.script_analysis.s.uBidiLevel;
270 widths[i] = p->member.run.nWidth;
271 TRACE( "%d: level %d width %d\n", i, levels[i], widths[i] );
272 i++;
273 }
274 }
275
276 ScriptLayout( num_runs, levels, vis_to_log, log_to_vis );
277
278 pos[0] = start->member.run.para->pt.x;
279 for (i = 1; i < num_runs; i++)
280 pos[i] = pos[i - 1] + widths[ vis_to_log[ i - 1 ] ];
281
282 for (i = 0, p = start; i < num_runs; p = p->next)
283 {
284 if (p->type == diRun)
285 {
286 p->member.run.pt.x = pos[ log_to_vis[ i ] ];
287 TRACE( "%d: x = %d\n", i, p->member.run.pt.x );
288 i++;
289 }
290 }
291
292 if (vis_to_log != buf) heap_free( vis_to_log );
293}
294
296{
298 ME_Paragraph *para = &wc->pPara->member.para;
299 BOOL bSkippingSpaces = TRUE;
300 int ascent = 0, descent = 0, width=0, shift = 0, align = 0;
301
302 /* Include height of para numbering label */
303 if (wc->nRow == 0 && para->fmt.wNumbering)
304 {
305 ascent = para->para_num.style->tm.tmAscent;
306 descent = para->para_num.style->tm.tmDescent;
307 }
308
309 for (p = pEnd->prev; p!=wc->pRowStart->prev; p = p->prev)
310 {
311 /* ENDPARA run shouldn't affect row height, except if it's the only run in the paragraph */
312 if (p->type==diRun && ((p==wc->pRowStart) || !(p->member.run.nFlags & MERF_ENDPARA))) { /* FIXME add more run types */
313 if (p->member.run.nAscent>ascent)
314 ascent = p->member.run.nAscent;
315 if (p->member.run.nDescent>descent)
316 descent = p->member.run.nDescent;
317 if (bSkippingSpaces)
318 {
319 /* Exclude space characters from run width.
320 * Other whitespace or delimiters are not treated this way. */
321 int len = p->member.run.len;
322 WCHAR *text = get_text( &p->member.run, len - 1 );
323
324 assert (len);
325 if (~p->member.run.nFlags & MERF_GRAPHICS)
326 while (len && *(text--) == ' ')
327 len--;
328 if (len)
329 {
330 if (len == p->member.run.len)
331 width += p->member.run.nWidth;
332 else
333 width += ME_PointFromCharContext( wc->context, &p->member.run, len, FALSE );
334 }
335 bSkippingSpaces = !len;
336 } else if (!(p->member.run.nFlags & MERF_ENDPARA))
337 width += p->member.run.nWidth;
338 }
339 }
340
341 para->nWidth = max(para->nWidth, width);
342 row = ME_MakeRow(ascent+descent, ascent, width);
343 if (wc->context->editor->bEmulateVersion10 && /* v1.0 - 3.0 */
344 (para->fmt.dwMask & PFM_TABLE) && (para->fmt.wEffects & PFE_TABLE))
345 {
346 /* The text was shifted down in ME_BeginRow so move the wrap context
347 * back to where it should be. */
348 wc->pt.y--;
349 /* The height of the row is increased by the borders. */
350 row->member.row.nHeight += 2;
351 }
352 row->member.row.pt = wc->pt;
353 row->member.row.nLMargin = (!wc->nRow ? wc->nFirstMargin : wc->nLeftMargin);
354 row->member.row.nRMargin = wc->nRightMargin;
356 align = para->fmt.wAlignment;
357 if (align == PFA_CENTER)
358 shift = max((wc->nAvailWidth-width)/2, 0);
359 if (align == PFA_RIGHT)
360 shift = max(wc->nAvailWidth-width, 0);
361
362 if (para->nFlags & MEPF_COMPLEX) layout_row( wc->pRowStart, pEnd );
363
364 row->member.row.pt.x = row->member.row.nLMargin + shift;
365 for (p = wc->pRowStart; p!=pEnd; p = p->next)
366 {
367 if (p->type==diRun) { /* FIXME add more run types */
368 p->member.run.pt.x += row->member.row.nLMargin+shift;
369 }
370 }
371
372 if (wc->nRow == 0 && para->fmt.wNumbering)
373 {
374 para->para_num.pt.x = wc->nParaNumOffset + shift;
375 para->para_num.pt.y = wc->pt.y + row->member.row.nBaseline;
376 }
377
379 wc->nRow++;
380 wc->pt.y += row->member.row.nHeight;
381 ME_BeginRow(wc);
382}
383
385{
386 ME_DisplayItem *para = wc->pPara;
387 PARAFORMAT2 *pFmt = &para->member.para.fmt;
388 if (wc->pRowStart)
389 ME_InsertRowStart(wc, p);
390 if (wc->context->editor->bEmulateVersion10 && /* v1.0 - 3.0 */
391 pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE)
392 {
393 /* ME_BeginRow was called an extra time for the paragraph, and it shifts the
394 * text down by one pixel for the border, so fix up the wrap context. */
395 wc->pt.y--;
396 }
397
398 /*
399 p = para->next;
400 while(p) {
401 if (p->type == diParagraph || p->type == diTextEnd)
402 return;
403 if (p->type == diRun)
404 {
405 ME_Run *run = &p->member.run;
406 TRACE("%s - (%d, %d)\n", debugstr_run(run), run->pt.x, run->pt.y);
407 }
408 p = p->next;
409 }
410 */
411}
412
414{
415 /* FIXME compose style (out of character and paragraph styles) here */
416
417 ME_UpdateRunFlags(wc->context->editor, &p->member.run);
418
420 wc->nRow ? wc->nLeftMargin : wc->nFirstMargin, &p->member.run);
421}
422
423
424static int find_non_whitespace(const WCHAR *s, int len, int start)
425{
426 int i;
427 for (i = start; i < len && ME_IsWSpace( s[i] ); i++)
428 ;
429
430 return i;
431}
432
433/* note: these two really return the first matching offset (starting from EOS)+1
434 * in other words, an offset of the first trailing white/black */
435
436/* note: returns offset of the first trailing whitespace */
438{
439 int i;
440 for (i = start; i > 0 && ME_IsWSpace( s[i - 1] ); i--)
441 ;
442
443 return i;
444}
445
446/* note: returns offset of the first trailing nonwhitespace */
447static int reverse_find_whitespace(const WCHAR *s, int start)
448{
449 int i;
450 for (i = start; i > 0 && !ME_IsWSpace( s[i - 1] ); i--)
451 ;
452
453 return i;
454}
455
457{
458 ME_DisplayItem *pp, *piter = p;
459 int j;
460 if (!i)
461 return NULL;
462 j = reverse_find_non_whitespace( get_text( &p->member.run, 0 ), i);
463 if (j>0) {
464 pp = split_run_extents(wc, piter, j);
465 wc->pt.x += piter->member.run.nWidth;
466 return pp;
467 }
468 else
469 {
470 pp = piter;
471 /* omit all spaces before split point */
472 while(piter != wc->pRowStart)
473 {
474 piter = ME_FindItemBack(piter, diRun);
475 if (piter->member.run.nFlags & MERF_WHITESPACE)
476 {
477 pp = piter;
478 continue;
479 }
480 if (piter->member.run.nFlags & MERF_ENDWHITE)
481 {
483 piter->member.run.len );
484 pp = split_run_extents(wc, piter, i);
485 wc->pt = pp->member.run.pt;
486 return pp;
487 }
488 /* this run is the end of spaces, so the run edge is a good point to split */
489 wc->pt = pp->member.run.pt;
490 wc->bOverflown = TRUE;
491 TRACE("Split point is: %s|%s\n", debugstr_run( &piter->member.run ), debugstr_run( &pp->member.run ));
492 return pp;
493 }
494 wc->pt = piter->member.run.pt;
495 return piter;
496 }
497}
498
500{
501 ME_DisplayItem *piter = p, *pp;
502 int i, idesp, len;
503 ME_Run *run = &p->member.run;
504
505 idesp = i = find_split_point( wc->context, loc, run );
506 len = run->len;
507 assert(len>0);
508 assert(i<len);
509 if (i) {
510 /* don't split words */
511 i = reverse_find_whitespace( get_text( run, 0 ), i );
512 pp = ME_MaximizeSplit(wc, p, i);
513 if (pp)
514 return pp;
515 }
516 TRACE("Must backtrack to split at: %s\n", debugstr_run( &p->member.run ));
517 if (wc->pLastSplittableRun)
518 {
520 {
521 wc->pt = wc->pLastSplittableRun->member.run.pt;
522 return wc->pLastSplittableRun;
523 }
525 {
526 /* the following two lines are just to check if we forgot to call UpdateRunFlags earlier,
527 they serve no other purpose */
530
531 piter = wc->pLastSplittableRun;
532 run = &piter->member.run;
533 len = run->len;
534 /* don't split words */
535 i = reverse_find_whitespace( get_text( run, 0 ), len );
536 if (i == len)
538 if (i) {
539 ME_DisplayItem *piter2 = split_run_extents(wc, piter, i);
540 wc->pt = piter2->member.run.pt;
541 return piter2;
542 }
543 /* splittable = must have whitespaces */
544 assert(0 == "Splittable, but no whitespaces");
545 }
546 else
547 {
548 /* restart from the first run beginning with spaces */
549 wc->pt = wc->pLastSplittableRun->member.run.pt;
550 return wc->pLastSplittableRun;
551 }
552 }
553 TRACE("Backtracking failed, trying desperate: %s\n", debugstr_run( &p->member.run ));
554 /* OK, no better idea, so assume we MAY split words if we can split at all*/
555 if (idesp)
556 return split_run_extents(wc, piter, idesp);
557 else
558 if (wc->pRowStart && piter != wc->pRowStart)
559 {
560 /* don't need to break current run, because it's possible to split
561 before this run */
562 wc->bOverflown = TRUE;
563 return piter;
564 }
565 else
566 {
567 /* split point inside first character - no choice but split after that char */
568 if (len != 1) {
569 /* the run is more than 1 char, so we may split */
570 return split_run_extents(wc, piter, 1);
571 }
572 /* the run is one char, can't split it */
573 return piter;
574 }
575}
576
578{
579 ME_DisplayItem *pp;
580 ME_Run *run;
581 int len;
582
583 assert(p->type == diRun);
584 if (!wc->pRowStart)
585 wc->pRowStart = p;
586 run = &p->member.run;
587 run->pt.x = wc->pt.x;
588 run->pt.y = wc->pt.y;
589 ME_WrapSizeRun(wc, p);
590 len = run->len;
591
592 if (wc->bOverflown) /* just skipping final whitespaces */
593 {
594 /* End paragraph run can't overflow to the next line by itself. */
595 if (run->nFlags & MERF_ENDPARA)
596 return p->next;
597
598 if (run->nFlags & MERF_WHITESPACE) {
599 wc->pt.x += run->nWidth;
600 /* skip runs consisting of only whitespaces */
601 return p->next;
602 }
603
604 if (run->nFlags & MERF_STARTWHITE) {
605 /* try to split the run at the first non-white char */
606 int black;
607 black = find_non_whitespace( get_text( run, 0 ), run->len, 0 );
608 if (black) {
609 wc->bOverflown = FALSE;
610 pp = split_run_extents(wc, p, black);
612 wc->nRow ? wc->nLeftMargin : wc->nFirstMargin,
613 &pp->member.run);
614 ME_InsertRowStart(wc, pp);
615 return pp;
616 }
617 }
618 /* black run: the row goes from pRowStart to the previous run */
619 ME_InsertRowStart(wc, p);
620 return p;
621 }
622 /* simply end the current row and move on to next one */
623 if (run->nFlags & MERF_ENDROW)
624 {
625 p = p->next;
626 ME_InsertRowStart(wc, p);
627 return p;
628 }
629
630 /* will current run fit? */
631 if (wc->bWordWrap &&
632 wc->pt.x + run->nWidth - wc->context->pt.x > wc->nAvailWidth)
633 {
634 int loc = wc->context->pt.x + wc->nAvailWidth - wc->pt.x;
635 /* total white run or end para */
636 if (run->nFlags & (MERF_WHITESPACE | MERF_ENDPARA)) {
637 /* let the overflow logic handle it */
638 wc->bOverflown = TRUE;
639 return p;
640 }
641 /* TAB: we can split before */
642 if (run->nFlags & MERF_TAB) {
643 wc->bOverflown = TRUE;
644 if (wc->pRowStart == p)
645 /* Don't split before the start of the run, or we will get an
646 * endless loop. */
647 return p->next;
648 else
649 return p;
650 }
651 /* graphics: we can split before, if run's width is smaller than row's width */
652 if ((run->nFlags & MERF_GRAPHICS) && run->nWidth <= wc->nAvailWidth) {
653 wc->bOverflown = TRUE;
654 return p;
655 }
656 /* can we separate out the last spaces ? (to use overflow logic later) */
657 if (run->nFlags & MERF_ENDWHITE)
658 {
659 /* we aren't sure if it's *really* necessary, it's a good start however */
660 int black = reverse_find_non_whitespace( get_text( run, 0 ), len );
661 split_run_extents(wc, p, black);
662 /* handle both parts again */
663 return p;
664 }
665 /* determine the split point by backtracking */
666 pp = ME_SplitByBacktracking(wc, p, loc);
667 if (pp == wc->pRowStart)
668 {
669 if (run->nFlags & MERF_STARTWHITE)
670 {
671 /* We had only spaces so far, so we must be on the first line of the
672 * paragraph (or the first line after MERF_ENDROW forced the line
673 * break within the paragraph), since no other lines of the paragraph
674 * start with spaces. */
675
676 /* The lines will only contain spaces, and the rest of the run will
677 * overflow onto the next line. */
678 wc->bOverflown = TRUE;
679 return p;
680 }
681 /* Couldn't split the first run, possible because we have a large font
682 * with a single character that caused an overflow.
683 */
684 wc->pt.x += run->nWidth;
685 return p->next;
686 }
687 if (p != pp) /* found a suitable split point */
688 {
689 wc->bOverflown = TRUE;
690 return pp;
691 }
692 /* we detected that it's best to split on start of this run */
693 if (wc->bOverflown)
694 return pp;
695 ERR("failure!\n");
696 /* not found anything - writing over margins is the only option left */
697 }
698 if ((run->nFlags & (MERF_SPLITTABLE | MERF_STARTWHITE))
699 || ((run->nFlags & (MERF_GRAPHICS|MERF_TAB)) && (p != wc->pRowStart)))
700 {
701 wc->pLastSplittableRun = p;
702 }
703 wc->pt.x += run->nWidth;
704 return p->next;
705}
706
708{
709 int sp = 0, ls = 0;
710 if (!(para->fmt.dwMask & PFM_LINESPACING)) return 0;
711
712 /* FIXME: how to compute simply the line space in ls ??? */
713 /* FIXME: does line spacing include the line itself ??? */
714 switch (para->fmt.bLineSpacingRule)
715 {
716 case 0: sp = ls; break;
717 case 1: sp = (3 * ls) / 2; break;
718 case 2: sp = 2 * ls; break;
719 case 3: sp = ME_twips2pointsY(c, para->fmt.dyLineSpacing); if (sp < ls) sp = ls; break;
720 case 4: sp = ME_twips2pointsY(c, para->fmt.dyLineSpacing); break;
721 case 5: sp = para->fmt.dyLineSpacing / 20; break;
722 default: FIXME("Unsupported spacing rule value %d\n", para->fmt.bLineSpacingRule);
723 }
724 if (c->editor->nZoomNumerator == 0)
725 return sp;
726 else
727 return sp * c->editor->nZoomNumerator / c->editor->nZoomDenominator;
728}
729
732
733 tp->member.para.nWidth = 0;
734 /* remove row start items as they will be reinserted by the
735 * paragraph wrapper anyway */
736 editor->total_rows -= tp->member.para.nRows;
737 tp->member.para.nRows = 0;
738 for (p = tp->next; p != tp->member.para.next_para; p = p->next) {
739 if (p->type == diStartRow) {
740 ME_DisplayItem *pRow = p;
741 p = p->prev;
742 ME_Remove(pRow);
744 }
745 }
746 /* join runs that can be joined */
747 for (p = tp->next; p != tp->member.para.next_para; p = p->next) {
748 assert(p->type != diStartRow); /* should have been deleted above */
749 if (p->type == diRun) {
750 while (p->next->type == diRun && /* FIXME */
751 ME_CanJoinRuns(&p->member.run, &p->next->member.run)) {
752 ME_JoinRuns(c->editor, p);
753 }
754 }
755 }
756}
757
759{
760 ME_Paragraph *para = &p->member.para;
761 ME_Run *run;
762 ME_DisplayItem *di;
763 SCRIPT_ITEM buf[16], *items = buf;
764 int items_passed = ARRAY_SIZE( buf ), num_items, cur_item;
766 FALSE, FALSE, 0 };
768 HRESULT hr;
769
770 assert( p->type == diParagraph );
771
772 if (para->fmt.dwMask & PFM_RTLPARA && para->fmt.wEffects & PFE_RTLPARA)
773 state.uBidiLevel = 1;
774
775 TRACE( "Base embedding level %d\n", state.uBidiLevel );
776
777 while (1)
778 {
779 hr = ScriptItemize( para->text->szData, para->text->nLen, items_passed, &control,
780 &state, items, &num_items );
781 if (hr != E_OUTOFMEMORY) break; /* may not be enough items if hr == E_OUTOFMEMORY */
782 if (items_passed > para->text->nLen + 1) break; /* something else has gone wrong */
783 items_passed *= 2;
784 if (items == buf)
785 items = heap_alloc( items_passed * sizeof( *items ) );
786 else
787 items = heap_realloc( items, items_passed * sizeof( *items ) );
788 if (!items) break;
789 }
790 if (FAILED( hr )) goto end;
791
792 if (TRACE_ON( richedit ))
793 {
794 TRACE( "got items:\n" );
795 for (cur_item = 0; cur_item < num_items; cur_item++)
796 {
797 TRACE( "\t%d - %d RTL %d bidi level %d\n", items[cur_item].iCharPos, items[cur_item+1].iCharPos - 1,
798 items[cur_item].a.fRTL, items[cur_item].a.s.uBidiLevel );
799 }
800
801 TRACE( "before splitting runs into ranges\n" );
802 for (di = p->next; di != p->member.para.next_para; di = di->next)
803 {
804 if (di->type != diRun) continue;
805 TRACE( "\t%d: %s\n", di->member.run.nCharOfs, debugstr_run( &di->member.run ) );
806 }
807 }
808
809 /* split runs into ranges at item boundaries */
810 for (di = p->next, cur_item = 0; di != p->member.para.next_para; di = di->next)
811 {
812 if (di->type != diRun) continue;
813 run = &di->member.run;
814
815 if (run->nCharOfs == items[cur_item+1].iCharPos) cur_item++;
816
817 items[cur_item].a.fLogicalOrder = TRUE;
818 run->script_analysis = items[cur_item].a;
819
820 if (run->nFlags & MERF_ENDPARA) break; /* don't split eop runs */
821
822 if (run->nCharOfs + run->len > items[cur_item+1].iCharPos)
823 {
824 ME_Cursor cursor = {p, di, items[cur_item+1].iCharPos - run->nCharOfs};
825 ME_SplitRunSimple( c->editor, &cursor );
826 }
827 }
828
829 if (TRACE_ON( richedit ))
830 {
831 TRACE( "after splitting into ranges\n" );
832 for (di = p->next; di != p->member.para.next_para; di = di->next)
833 {
834 if (di->type != diRun) continue;
835 TRACE( "\t%d: %s\n", di->member.run.nCharOfs, debugstr_run( &di->member.run ) );
836 }
837 }
838
839 para->nFlags |= MEPF_COMPLEX;
840
841end:
842 if (items != buf) heap_free( items );
843 return hr;
844}
845
846
848{
849 ME_DisplayItem *di;
850 ME_Run *run;
851 HRESULT hr;
852
853 for (di = p->next; di != p->member.para.next_para; di = di->next)
854 {
855 if (di->type != diRun) continue;
856 run = &di->member.run;
857
858 hr = shape_run( c, run );
859 if (FAILED( hr ))
860 {
861 run->para->nFlags &= ~MEPF_COMPLEX;
862 return hr;
863 }
864 }
865 return hr;
866}
867
871 int border = 0;
872 int linespace = 0;
873 PARAFORMAT2 *pFmt;
874
875 assert(tp->type == diParagraph);
876 if (!(tp->member.para.nFlags & MEPF_REWRAP)) {
877 return;
878 }
880
881 /* Calculate paragraph numbering label */
882 para_num_init( c, &tp->member.para );
883
884 /* For now treating all non-password text as complex for better testing */
885 if (!c->editor->cPasswordMask /* &&
886 ScriptIsComplex( tp->member.para.text->szData, tp->member.para.text->nLen, SIC_COMPLEX ) == S_OK */)
887 {
888 if (SUCCEEDED( itemize_para( c, tp ) ))
889 shape_para( c, tp );
890 }
891
892 pFmt = &tp->member.para.fmt;
893
894 wc.context = c;
895 wc.pPara = tp;
896/* wc.para_style = tp->member.para.style; */
897 wc.style = NULL;
898 wc.nParaNumOffset = 0;
899 if (tp->member.para.nFlags & MEPF_ROWEND) {
900 wc.nFirstMargin = wc.nLeftMargin = wc.nRightMargin = 0;
901 } else {
902 int dxStartIndent = pFmt->dxStartIndent;
903 if (tp->member.para.pCell) {
904 dxStartIndent += ME_GetTableRowEnd(tp)->member.para.fmt.dxOffset;
905 }
906 wc.nLeftMargin = ME_twips2pointsX(c, dxStartIndent + pFmt->dxOffset);
907 wc.nFirstMargin = ME_twips2pointsX(c, dxStartIndent);
908 if (pFmt->wNumbering)
909 {
911 dxStartIndent = max( ME_twips2pointsX(c, pFmt->wNumberingTab),
912 tp->member.para.para_num.width );
913 wc.nFirstMargin += dxStartIndent;
914 }
916
917 if (wc.nFirstMargin < 0)
918 wc.nFirstMargin = 0;
919 if (wc.nLeftMargin < 0)
920 wc.nLeftMargin = 0;
921 }
922 if (c->editor->bEmulateVersion10 && /* v1.0 - 3.0 */
923 pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE)
924 {
925 wc.nFirstMargin += ME_twips2pointsX(c, pFmt->dxOffset * 2);
926 }
927 wc.nRow = 0;
928 wc.pt.y = 0;
929 if (pFmt->dwMask & PFM_SPACEBEFORE)
930 wc.pt.y += ME_twips2pointsY(c, pFmt->dySpaceBefore);
931 if (!(pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE) &&
932 pFmt->dwMask & PFM_BORDER)
933 {
934 border = ME_GetParaBorderWidth(c, tp->member.para.fmt.wBorders);
935 if (pFmt->wBorders & 1) {
936 wc.nFirstMargin += border;
937 wc.nLeftMargin += border;
938 }
939 if (pFmt->wBorders & 2)
940 wc.nRightMargin -= border;
941 if (pFmt->wBorders & 4)
942 wc.pt.y += border;
943 }
944
945 linespace = ME_GetParaLineSpace(c, &tp->member.para);
946
947 ME_BeginRow(&wc);
948 for (p = tp->next; p!=tp->member.para.next_para; ) {
949 assert(p->type != diStartRow);
950 if (p->type == diRun) {
951 p = ME_WrapHandleRun(&wc, p);
952 }
953 else p = p->next;
954 if (wc.nRow && p == wc.pRowStart)
955 wc.pt.y += linespace;
956 }
958 if (!(pFmt->dwMask & PFM_TABLE && pFmt->wEffects & PFE_TABLE) &&
959 (pFmt->dwMask & PFM_BORDER) && (pFmt->wBorders & 8))
960 wc.pt.y += border;
961 if (tp->member.para.fmt.dwMask & PFM_SPACEAFTER)
962 wc.pt.y += ME_twips2pointsY(c, pFmt->dySpaceAfter);
963
964 tp->member.para.nFlags &= ~MEPF_REWRAP;
965 tp->member.para.nHeight = wc.pt.y;
966 tp->member.para.nRows = wc.nRow;
967 editor->total_rows += wc.nRow;
968}
969
971 ME_DisplayItem **repaint_start,
972 ME_DisplayItem **repaint_end)
973{
974 if (!*repaint_start)
975 *repaint_start = para;
976 *repaint_end = para;
977}
978
979static void adjust_para_y(ME_DisplayItem *item, ME_Context *c, ME_DisplayItem *repaint_start, ME_DisplayItem *repaint_end)
980{
981 if (item->member.para.nFlags & MEPF_ROWSTART)
982 {
984 ME_DisplayItem *endRowPara;
985 int borderWidth = 0;
986 cell->member.cell.pt = c->pt;
987 /* Offset the text by the largest top border width. */
988 while (cell->member.cell.next_cell)
989 {
990 borderWidth = max(borderWidth, cell->member.cell.border.top.width);
991 cell = cell->member.cell.next_cell;
992 }
993 endRowPara = ME_FindItemFwd(cell, diParagraph);
994 assert(endRowPara->member.para.nFlags & MEPF_ROWEND);
995 if (borderWidth > 0)
996 {
997 borderWidth = max(ME_twips2pointsY(c, borderWidth), 1);
998 while (cell)
999 {
1000 cell->member.cell.yTextOffset = borderWidth;
1001 cell = cell->member.cell.prev_cell;
1002 }
1003 c->pt.y += borderWidth;
1004 }
1005 if (endRowPara->member.para.fmt.dxStartIndent > 0)
1006 {
1007 int dxStartIndent = endRowPara->member.para.fmt.dxStartIndent;
1008 cell = ME_FindItemFwd(item, diCell);
1009 cell->member.cell.pt.x += ME_twips2pointsX(c, dxStartIndent);
1010 c->pt.x = cell->member.cell.pt.x;
1011 }
1012 }
1013 else if (item->member.para.nFlags & MEPF_ROWEND)
1014 {
1015 /* Set all the cells to the height of the largest cell */
1016 ME_DisplayItem *startRowPara;
1017 int prevHeight, nHeight, bottomBorder = 0;
1019 item->member.para.nWidth = cell->member.cell.pt.x + cell->member.cell.nWidth;
1020 if (!(item->member.para.next_para->member.para.nFlags & MEPF_ROWSTART))
1021 {
1022 /* Last row, the bottom border is added to the height. */
1023 cell = cell->member.cell.prev_cell;
1024 while (cell)
1025 {
1026 bottomBorder = max(bottomBorder, cell->member.cell.border.bottom.width);
1027 cell = cell->member.cell.prev_cell;
1028 }
1029 bottomBorder = ME_twips2pointsY(c, bottomBorder);
1030 cell = ME_FindItemBack(item, diCell);
1031 }
1032 prevHeight = cell->member.cell.nHeight;
1033 nHeight = cell->member.cell.prev_cell->member.cell.nHeight + bottomBorder;
1034 cell->member.cell.nHeight = nHeight;
1035 item->member.para.nHeight = nHeight;
1036 cell = cell->member.cell.prev_cell;
1037 cell->member.cell.nHeight = nHeight;
1038 while (cell->member.cell.prev_cell)
1039 {
1040 cell = cell->member.cell.prev_cell;
1041 cell->member.cell.nHeight = nHeight;
1042 }
1043 /* Also set the height of the start row paragraph */
1044 startRowPara = ME_FindItemBack(cell, diParagraph);
1045 startRowPara->member.para.nHeight = nHeight;
1046 c->pt.x = startRowPara->member.para.pt.x;
1047 c->pt.y = cell->member.cell.pt.y + nHeight;
1048 if (prevHeight < nHeight)
1049 {
1050 /* The height of the cells has grown, so invalidate the bottom of
1051 * the cells. */
1052 ME_MarkRepaintEnd(item, &repaint_start, &repaint_end);
1053 cell = ME_FindItemBack(item, diCell);
1054 while (cell)
1055 {
1056 ME_MarkRepaintEnd(ME_FindItemBack(cell, diParagraph), &repaint_start, &repaint_end);
1057 cell = cell->member.cell.prev_cell;
1058 }
1059 }
1060 }
1061 else if (item->member.para.pCell &&
1062 item->member.para.pCell != item->member.para.next_para->member.para.pCell)
1063 {
1064 /* The next paragraph is in the next cell in the table row. */
1065 ME_Cell *cell = &item->member.para.pCell->member.cell;
1066 cell->nHeight = c->pt.y + item->member.para.nHeight - cell->pt.y;
1067
1068 /* Propagate the largest height to the end so that it can be easily
1069 * sent back to all the cells at the end of the row. */
1070 if (cell->prev_cell)
1071 cell->nHeight = max(cell->nHeight, cell->prev_cell->member.cell.nHeight);
1072
1073 c->pt.x = cell->pt.x + cell->nWidth;
1074 c->pt.y = cell->pt.y;
1075 cell->next_cell->member.cell.pt = c->pt;
1076 if (!(item->member.para.next_para->member.para.nFlags & MEPF_ROWEND))
1077 c->pt.y += cell->yTextOffset;
1078 }
1079 else
1080 {
1081 if (item->member.para.pCell)
1082 {
1083 /* Next paragraph in the same cell. */
1084 c->pt.x = item->member.para.pCell->member.cell.pt.x;
1085 }
1086 else
1087 /* Normal paragraph */
1088 c->pt.x = 0;
1089 c->pt.y += item->member.para.nHeight;
1090 }
1091}
1092
1094{
1096 ME_Context c;
1097 int totalWidth = editor->nTotalWidth, diff = 0, prev_width;
1098 ME_DisplayItem *repaint_start = NULL, *repaint_end = NULL;
1099 ME_Paragraph *para;
1100
1101 if (!editor->first_marked_para)
1102 return FALSE;
1103
1104 ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost));
1105
1106 item = editor->first_marked_para;
1107 c.pt = item->member.para.pt;
1108 while (item != editor->pBuffer->pLast)
1109 {
1110 assert(item->type == diParagraph);
1111
1112 prev_width = item->member.para.nWidth;
1113 ME_WrapTextParagraph(editor, &c, item);
1114 if (prev_width == totalWidth && item->member.para.nWidth < totalWidth)
1115 totalWidth = get_total_width(editor);
1116 else
1117 totalWidth = max(totalWidth, item->member.para.nWidth);
1118
1119 if (!item->member.para.nCharOfs)
1120 ME_MarkRepaintEnd(item->member.para.prev_para, &repaint_start, &repaint_end);
1121 ME_MarkRepaintEnd(item, &repaint_start, &repaint_end);
1122 adjust_para_y(item, &c, repaint_start, repaint_end);
1123
1124 if (item->member.para.next_para)
1125 {
1126 diff = c.pt.y - item->member.para.next_para->member.para.pt.y;
1127 if (diff)
1128 {
1129 para = &item->member.para;
1130 while (para->next_para && para != &item->member.para.next_marked->member.para &&
1131 para != &editor->pBuffer->pLast->member.para)
1132 {
1133 ME_MarkRepaintEnd(para->next_para, &repaint_start, &repaint_end);
1134 para->next_para->member.para.pt.y = c.pt.y;
1135 adjust_para_y(para->next_para, &c, repaint_start, repaint_end);
1136 para = &para->next_para->member.para;
1137 }
1138 }
1139 }
1140 if (item->member.para.next_marked)
1141 {
1142 ME_DisplayItem *rem = item;
1143 item = item->member.para.next_marked;
1144 remove_marked_para(editor, rem);
1145 }
1146 else
1147 {
1148 remove_marked_para(editor, item);
1149 item = editor->pBuffer->pLast;
1150 }
1151 c.pt.y = item->member.para.pt.y;
1152 }
1153 editor->sizeWindow.cx = c.rcView.right-c.rcView.left;
1154 editor->sizeWindow.cy = c.rcView.bottom-c.rcView.top;
1155
1156 editor->nTotalLength = c.pt.y;
1157 editor->nTotalWidth = totalWidth;
1158 editor->pBuffer->pLast->member.para.pt.x = 0;
1159 editor->pBuffer->pLast->member.para.pt.y = c.pt.y;
1160
1162
1163 if (repaint_start || editor->nTotalLength < editor->nLastTotalLength)
1164 ME_InvalidateParagraphRange(editor, repaint_start, repaint_end);
1165 return !!repaint_start;
1166}
1167
1169 ME_DisplayItem *start_para,
1170 ME_DisplayItem *last_para)
1171{
1172 ME_Context c;
1173 RECT rc;
1174 int ofs;
1175
1176 ME_InitContext(&c, editor, ITextHost_TxGetDC(editor->texthost));
1177 rc = c.rcView;
1178 ofs = editor->vert_si.nPos;
1179
1180 if (start_para) {
1181 start_para = ME_GetOuterParagraph(start_para);
1182 last_para = ME_GetOuterParagraph(last_para);
1183 rc.top = c.rcView.top + start_para->member.para.pt.y - ofs;
1184 } else {
1185 rc.top = c.rcView.top + editor->nTotalLength - ofs;
1186 }
1187 if (editor->nTotalLength < editor->nLastTotalLength)
1188 rc.bottom = c.rcView.top + editor->nLastTotalLength - ofs;
1189 else
1190 rc.bottom = c.rcView.top + last_para->member.para.pt.y + last_para->member.para.nHeight - ofs;
1192
1194}
1195
1196
1197void
1199{
1200 if (editor->nEventMask & ENM_REQUESTRESIZE)
1201 {
1202 RECT rc;
1203
1204 ITextHost_TxGetClientRect(editor->texthost, &rc);
1205
1206 if (force || rc.bottom != editor->nTotalLength)
1207 {
1209
1210 info.nmhdr.hwndFrom = NULL;
1211 info.nmhdr.idFrom = 0;
1212 info.nmhdr.code = EN_REQUESTRESIZE;
1213 info.rc = rc;
1214 info.rc.right = editor->nTotalWidth;
1215 info.rc.bottom = editor->nTotalLength;
1216
1217 editor->nEventMask &= ~ENM_REQUESTRESIZE;
1218 ITextHost_TxNotify(editor->texthost, info.nmhdr.code, &info);
1219 editor->nEventMask |= ENM_REQUESTRESIZE;
1220 }
1221 }
1222}
static int state
Definition: maze.c:121
static void * heap_alloc(size_t len)
Definition: appwiz.h:66
static BOOL heap_free(void *mem)
Definition: appwiz.h:76
static void * heap_realloc(void *mem, size_t len)
Definition: appwiz.h:71
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
void ls(int argc, const char *argv[])
Definition: cmds.c:1136
#define ARRAY_SIZE(A)
Definition: main.h:20
#define FIXME(fmt,...)
Definition: precomp.h:53
#define ERR(fmt,...)
Definition: precomp.h:57
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define TRACE_ON(x)
Definition: compat.h:75
const WCHAR * text
Definition: package.c:1794
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
HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs, int cGlyphs, const SCRIPT_VISATTR *psva, SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC)
Definition: usp10.c:3510
HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItems, const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState, SCRIPT_ITEM *pItems, int *pcItems)
Definition: usp10.c:1853
HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars, int cChars, int cMaxGlyphs, SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust, SCRIPT_VISATTR *psva, int *pcGlyphs)
Definition: usp10.c:3321
HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
Definition: usp10.c:3752
struct png_info_def *typedef unsigned char **typedef struct png_info_def *typedef struct png_info_def *typedef struct png_info_def *typedef unsigned char ** row
Definition: typeof.h:78
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
#define assert(x)
Definition: debug.h:53
_In_ uint64_t _In_ uint64_t _In_ uint64_t _In_opt_ traverse_ptr * tp
Definition: btrfs.c:2996
int align(int length, int align)
Definition: dsound8.c:36
void ME_JoinRuns(ME_TextEditor *editor, ME_DisplayItem *p) DECLSPEC_HIDDEN
Definition: run.c:229
int ME_PointFromCharContext(ME_Context *c, ME_Run *pRun, int nOffset, BOOL visual_order) DECLSPEC_HIDDEN
Definition: run.c:557
#define ITextHost_TxInvalidateRect(This, a, b)
Definition: editor.h:293
void ME_CheckCharOffsets(ME_TextEditor *editor) DECLSPEC_HIDDEN
Definition: run.c:101
int ME_CharFromPointContext(ME_Context *c, int cx, ME_Run *run, BOOL closest, BOOL visual_order) DECLSPEC_HIDDEN
Definition: run.c:462
int get_total_width(ME_TextEditor *editor) DECLSPEC_HIDDEN
Definition: para.c:64
void ME_DestroyDisplayItem(ME_DisplayItem *item) DECLSPEC_HIDDEN
Definition: list.c:160
int ME_GetParaBorderWidth(const ME_Context *c, int flags) DECLSPEC_HIDDEN
Definition: paint.c:529
int ME_twips2pointsY(const ME_Context *c, int y) DECLSPEC_HIDDEN
Definition: paint.c:161
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_SplitRunSimple(ME_TextEditor *editor, ME_Cursor *cursor) DECLSPEC_HIDDEN
Definition: run.c:258
#define ITextHost_TxNotify(This, a, b)
Definition: editor.h:322
ME_DisplayItem * ME_GetOuterParagraph(ME_DisplayItem *para) DECLSPEC_HIDDEN
Definition: table.c:172
SIZE ME_GetRunSizeCommon(ME_Context *c, const ME_Paragraph *para, ME_Run *run, int nLen, int startx, int *pAscent, int *pDescent) DECLSPEC_HIDDEN
Definition: run.c:616
#define ITextHost_TxGetClientRect(This, a)
Definition: editor.h:308
void remove_marked_para(ME_TextEditor *editor, ME_DisplayItem *para) DECLSPEC_HIDDEN
Definition: para.c:82
#define ITextHost_TxGetDC(This)
Definition: editor.h:287
void para_num_init(ME_Context *c, ME_Paragraph *para) DECLSPEC_HIDDEN
Definition: para.c:395
static int ME_IsWSpace(WCHAR ch)
Definition: editor.h:101
void ME_Remove(ME_DisplayItem *diWhere) DECLSPEC_HIDDEN
Definition: list.c:35
void ME_InsertBefore(ME_DisplayItem *diWhere, ME_DisplayItem *diWhat) DECLSPEC_HIDDEN
Definition: list.c:26
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_CanJoinRuns(const ME_Run *run1, const ME_Run *run2) DECLSPEC_HIDDEN
Definition: run.c:35
static const char * debugstr_run(const ME_Run *run)
Definition: editor.h:46
void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run) DECLSPEC_HIDDEN
Definition: run.c:413
ME_DisplayItem * ME_GetTableRowEnd(ME_DisplayItem *para) DECLSPEC_HIDDEN
Definition: table.c:136
#define MERF_STARTWHITE
Definition: editstr.h:116
#define MERF_TAB
Definition: editstr.h:107
#define MERF_ENDPARA
Definition: editstr.h:122
#define MERF_ENDWHITE
Definition: editstr.h:118
#define MERF_HIDDEN
Definition: editstr.h:126
#define MERF_GRAPHICS
Definition: editstr.h:105
#define MEPF_ROWSTART
Definition: editstr.h:144
#define MEPF_ROWEND
Definition: editstr.h:145
#define MEPF_COMPLEX
Definition: editstr.h:146
@ diStartRow
Definition: editstr.h:88
@ diCell
Definition: editstr.h:86
@ diRun
Definition: editstr.h:87
@ diParagraph
Definition: editstr.h:85
#define MERF_SPLITTABLE
Definition: editstr.h:114
#define MEPF_REWRAP
Definition: editstr.h:141
#define MERF_ENDROW
Definition: editstr.h:124
#define MERF_WHITESPACE
Definition: editstr.h:120
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned short WORD
Definition: ntddk_ex.h:93
GLint GLint GLsizei GLsizei GLsizei GLint border
Definition: gl.h:1546
GLuint start
Definition: gl.h:1545
GLdouble s
Definition: gl.h:2039
GLuint GLuint end
Definition: gl.h:1545
GLint GLint GLsizei GLsizei height
Definition: gl.h:1546
GLint GLint GLsizei width
Definition: gl.h:1546
GLsizeiptr size
Definition: glext.h:5919
const GLubyte * c
Definition: glext.h:8905
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLsizei levels
Definition: glext.h:7884
GLfloat GLfloat p
Definition: glext.h:8902
GLenum GLsizei len
Definition: glext.h:6722
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
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
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 GLint GLint j
Definition: glfuncs.h:250
const char cursor[]
Definition: icontest.c:13
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
#define c
Definition: ke_i.h:80
static const WCHAR sp[]
Definition: suminfo.c:287
static ATOM item
Definition: dde.c:856
#define shift
Definition: input.c:1755
static TCHAR * items[]
Definition: page1.c:45
_Out_opt_ int * cx
Definition: commctrl.h:585
#define PFM_SPACEBEFORE
Definition: richedit.h:847
#define PFA_RIGHT
Definition: richedit.h:922
#define PFA_CENTER
Definition: richedit.h:923
#define PFE_RTLPARA
Definition: richedit.h:932
#define PFM_LINESPACING
Definition: richedit.h:849
#define EN_REQUESTRESIZE
Definition: richedit.h:192
#define PFM_TABLE
Definition: richedit.h:870
#define PFE_TABLE
Definition: richedit.h:944
#define PFM_BORDER
Definition: richedit.h:851
#define PFM_ALIGNMENT
Definition: richedit.h:841
#define PFM_RTLPARA
Definition: richedit.h:856
#define PFM_SPACEAFTER
Definition: richedit.h:848
#define ENM_REQUESTRESIZE
Definition: richedit.h:477
HRESULT hr
Definition: shlfolder.c:183
#define TRACE(s)
Definition: solgame.cpp:4
LONG cx
Definition: kdterminal.h:27
LONG cy
Definition: kdterminal.h:28
LONG dySpaceBefore
Definition: richedit.h:676
BYTE bLineSpacingRule
Definition: richedit.h:678
WORD wAlignment
Definition: richedit.h:673
LONG dxRightIndent
Definition: richedit.h:671
DWORD dwMask
Definition: richedit.h:667
LONG dyLineSpacing
Definition: richedit.h:676
LONG dySpaceAfter
Definition: richedit.h:676
LONG dxOffset
Definition: richedit.h:672
WORD wBorders
Definition: richedit.h:681
WORD wNumbering
Definition: richedit.h:668
WORD wEffects
Definition: richedit.h:669
LONG dxStartIndent
Definition: richedit.h:670
WORD wNumberingTab
Definition: richedit.h:680
Definition: dialog.c:52
struct define * next
Definition: compiler.c:65
ME_Border bottom
Definition: editstr.h:190
ME_Border top
Definition: editstr.h:188
struct tagME_DisplayItem * prev_cell
Definition: editstr.h:229
POINT pt
Definition: editstr.h:226
int nHeight
Definition: editstr.h:227
int nRightBoundary
Definition: editstr.h:224
struct tagME_DisplayItem * next_cell
Definition: editstr.h:229
ME_BorderRect border
Definition: editstr.h:225
int yTextOffset
Definition: editstr.h:228
int nWidth
Definition: editstr.h:227
int nAvailWidth
Definition: editstr.h:457
POINT pt
Definition: editstr.h:454
ME_TextEditor * editor
Definition: editstr.h:462
union tagME_DisplayItem::@535 member
ME_DIType type
Definition: editstr.h:256
struct tagME_DisplayItem * prev
Definition: editstr.h:257
ME_Cell cell
Definition: editstr.h:261
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
ME_String * text
Definition: editstr.h:205
PARAFORMAT2 fmt
Definition: editstr.h:204
struct tagME_DisplayItem * pCell
Definition: editstr.h:207
int nAscent
Definition: editstr.h:166
int num_glyphs
Definition: editstr.h:171
POINT pt
Definition: editstr.h:167
GOFFSET * offsets
Definition: editstr.h:175
int nCharOfs
Definition: editstr.h:162
int nDescent
Definition: editstr.h:166
SCRIPT_VISATTR * vis_attrs
Definition: editstr.h:173
int max_clusters
Definition: editstr.h:176
struct tagME_Paragraph * para
Definition: editstr.h:161
int * advances
Definition: editstr.h:174
WORD * glyphs
Definition: editstr.h:172
ME_Style * style
Definition: editstr.h:160
SCRIPT_ANALYSIS script_analysis
Definition: editstr.h:170
int nWidth
Definition: editstr.h:164
int max_glyphs
Definition: editstr.h:171
int nFlags
Definition: editstr.h:165
int len
Definition: editstr.h:163
WORD * clusters
Definition: editstr.h:177
WCHAR * szData
Definition: editstr.h:56
int nLen
Definition: editstr.h:57
SCRIPT_CACHE script_cache
Definition: editstr.h:78
ME_DisplayItem * pLast
Definition: editstr.h:268
SCROLLINFO vert_si
Definition: editstr.h:441
ITextHost * texthost
Definition: editstr.h:383
ME_DisplayItem * first_marked_para
Definition: editstr.h:435
ME_TextBuffer * pBuffer
Definition: editstr.h:386
BOOL bEmulateVersion10
Definition: editstr.h:385
int nLastTotalLength
Definition: editstr.h:392
ME_DisplayItem * pLastSplittableRun
Definition: wrap.c:49
int nLeftMargin
Definition: wrap.c:39
int nAvailWidth
Definition: wrap.c:42
int nRightMargin
Definition: wrap.c:39
ME_DisplayItem * pRowStart
Definition: wrap.c:47
ME_DisplayItem * pPara
Definition: wrap.c:46
int nFirstMargin
Definition: wrap.c:40
ME_Style * style
Definition: wrap.c:37
int nParaNumOffset
Definition: wrap.c:41
POINT pt
Definition: wrap.c:44
BOOL bOverflown
Definition: wrap.c:45
ME_Context * context
Definition: wrap.c:38
BOOL bWordWrap
Definition: wrap.c:45
long y
Definition: polytest.cpp:48
long x
Definition: polytest.cpp:48
LONG bottom
Definition: windef.h:309
LONG top
Definition: windef.h:307
#define max(a, b)
Definition: svc.c:63
#define LANG_USER_DEFAULT
Definition: tnerror.cpp:50
static int ME_GetParaLineSpace(ME_Context *c, ME_Paragraph *para)
Definition: wrap.c:707
static void calc_run_extent(ME_Context *c, const ME_Paragraph *para, int startx, ME_Run *run)
Definition: wrap.c:115
static void ME_WrapSizeRun(ME_WrapContext *wc, ME_DisplayItem *p)
Definition: wrap.c:413
static ME_DisplayItem * ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem *p, int loc)
Definition: wrap.c:499
static void adjust_para_y(ME_DisplayItem *item, ME_Context *c, ME_DisplayItem *repaint_start, ME_DisplayItem *repaint_end)
Definition: wrap.c:979
static int reverse_find_whitespace(const WCHAR *s, int start)
Definition: wrap.c:447
static int reverse_find_non_whitespace(const WCHAR *s, int start)
Definition: wrap.c:437
static ME_DisplayItem * ME_MaximizeSplit(ME_WrapContext *wc, ME_DisplayItem *p, int i)
Definition: wrap.c:456
static void ME_WrapEndParagraph(ME_WrapContext *wc, ME_DisplayItem *p)
Definition: wrap.c:384
BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor)
Definition: wrap.c:1093
static HRESULT itemize_para(ME_Context *c, ME_DisplayItem *p)
Definition: wrap.c:758
void ME_SendRequestResize(ME_TextEditor *editor, BOOL force)
Definition: wrap.c:1198
static void ME_PrepareParagraphForWrapping(ME_TextEditor *editor, ME_Context *c, ME_DisplayItem *tp)
Definition: wrap.c:730
static HRESULT shape_run(ME_Context *c, ME_Run *run)
Definition: wrap.c:65
static BOOL get_run_glyph_buffers(ME_Run *run)
Definition: wrap.c:52
static ME_DisplayItem * split_run_extents(ME_WrapContext *wc, ME_DisplayItem *item, int nVChar)
Definition: wrap.c:131
static HRESULT shape_para(ME_Context *c, ME_DisplayItem *p)
Definition: wrap.c:847
static void ME_InsertRowStart(ME_WrapContext *wc, const ME_DisplayItem *pEnd)
Definition: wrap.c:295
static ME_DisplayItem * ME_MakeRow(int height, int baseline, int width)
Definition: wrap.c:180
void ME_InvalidateParagraphRange(ME_TextEditor *editor, ME_DisplayItem *start_para, ME_DisplayItem *last_para)
Definition: wrap.c:1168
static void ME_MarkRepaintEnd(ME_DisplayItem *para, ME_DisplayItem **repaint_start, ME_DisplayItem **repaint_end)
Definition: wrap.c:970
static void layout_row(ME_DisplayItem *start, const ME_DisplayItem *end)
Definition: wrap.c:236
static ME_DisplayItem * ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
Definition: wrap.c:577
struct tagME_WrapContext ME_WrapContext
static int find_non_whitespace(const WCHAR *s, int len, int start)
Definition: wrap.c:424
static void ME_BeginRow(ME_WrapContext *wc)
Definition: wrap.c:190
static int find_split_point(ME_Context *c, int cx, ME_Run *run)
Definition: wrap.c:174
static void ME_WrapTextParagraph(ME_TextEditor *editor, ME_Context *c, ME_DisplayItem *tp)
Definition: wrap.c:868
__wchar_t WCHAR
Definition: xmlstorage.h:180
unsigned char BYTE
Definition: xxhash.c:193