ReactOS  0.4.14-dev-606-g14ebc0b
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 
35 typedef 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 */
74  get_run_glyph_buffers( run );
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;
92  get_run_glyph_buffers( run );
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  */
115 static 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  */
174 static 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 
180 static 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 
190 static void ME_BeginRow(ME_WrapContext *wc)
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;
198  wc->pLastSplittableRun = NULL;
199  wc->bWordWrap = wc->context->editor->bWordWrap;
200  if (para->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND)) {
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 {
226  wc->nAvailWidth = wc->context->nAvailWidth
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 {
238  ME_DisplayItem *p;
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 
295 static void ME_InsertRowStart(ME_WrapContext *wc, const ME_DisplayItem *pEnd)
296 {
297  ME_DisplayItem *p, *row;
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;
355  assert(para->fmt.dwMask & PFM_ALIGNMENT);
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 
424 static 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 */
437 static int reverse_find_non_whitespace(const WCHAR *s, int start)
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 */
447 static 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 */
528  ME_UpdateRunFlags(wc->context->editor, run);
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)
537  i = reverse_find_non_whitespace( get_text( run, 0 ), 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 {
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 
731  ME_DisplayItem *p;
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);
743  ME_DestroyDisplayItem(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 };
767  SCRIPT_STATE state = { 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0, 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 
841 end:
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 
869  ME_DisplayItem *p;
870  ME_WrapContext wc;
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  }
957  ME_WrapEndParagraph(&wc, p);
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 
979 static 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 
1161  ME_DestroyContext(&c);
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;
1191  ITextHost_TxInvalidateRect(editor->texthost, &rc, TRUE);
1192 
1193  ME_DestroyContext(&c);
1194 }
1195 
1196 
1197 void
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  {
1208  REQRESIZE info;
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 }
ME_DIType type
Definition: editstr.h:260
#define PFA_RIGHT
Definition: richedit.h:922
#define MEPF_ROWEND
Definition: editstr.h:149
#define PFM_SPACEBEFORE
Definition: richedit.h:847
#define PFM_RTLPARA
Definition: richedit.h:856
static int find_split_point(ME_Context *c, int cx, ME_Run *run)
Definition: wrap.c:174
#define ITextHost_TxInvalidateRect(This, a, b)
Definition: editor.h:293
#define PFM_BORDER
Definition: richedit.h:851
GLint GLint GLsizei width
Definition: gl.h:1546
#define max(a, b)
Definition: svc.c:63
ME_Paragraph para
Definition: editstr.h:266
void ME_CheckCharOffsets(ME_TextEditor *editor) DECLSPEC_HIDDEN
Definition: run.c:101
#define TRUE
Definition: types.h:120
#define shift
Definition: input.c:1761
ME_Border top
Definition: editstr.h:192
long y
Definition: polytest.cpp:48
WCHAR * szData
Definition: editstr.h:60
HRESULT hr
Definition: shlfolder.c:183
ME_DisplayItem * pLastSplittableRun
Definition: wrap.c:49
long x
Definition: polytest.cpp:48
static void ME_InsertRowStart(ME_WrapContext *wc, const ME_DisplayItem *pEnd)
Definition: wrap.c:295
GLsizei levels
Definition: glext.h:7884
static ME_DisplayItem * ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem *p, int loc)
Definition: wrap.c:499
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
ME_DisplayItem * ME_GetOuterParagraph(ME_DisplayItem *para) DECLSPEC_HIDDEN
Definition: table.c:172
static int reverse_find_whitespace(const WCHAR *s, int start)
Definition: wrap.c:447
const WCHAR * text
Definition: package.c:1827
static int reverse_find_non_whitespace(const WCHAR *s, int start)
Definition: wrap.c:437
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
ME_TextEditor * editor
Definition: editstr.h:464
#define MERF_STARTWHITE
Definition: editstr.h:120
struct tagME_DisplayItem * pCell
Definition: editstr.h:211
ME_Context * context
Definition: wrap.c:38
WORD wAlignment
Definition: richedit.h:673
#define MERF_GRAPHICS
Definition: editstr.h:109
#define PFM_SPACEAFTER
Definition: richedit.h:848
struct tagME_Paragraph * para
Definition: editstr.h:165
LONG top
Definition: windef.h:307
static HRESULT itemize_para(ME_Context *c, ME_DisplayItem *p)
Definition: wrap.c:758
#define PFM_ALIGNMENT
Definition: richedit.h:841
HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
Definition: usp10.c:3752
#define assert(x)
Definition: debug.h:53
ME_DisplayItem * ME_SplitRunSimple(ME_TextEditor *editor, ME_Cursor *cursor) DECLSPEC_HIDDEN
Definition: run.c:258
WORD * clusters
Definition: editstr.h:181
POINT pt
Definition: editstr.h:230
static int ME_GetParaLineSpace(ME_Context *c, ME_Paragraph *para)
Definition: wrap.c:707
GLuint GLuint end
Definition: gl.h:1545
ME_DisplayItem * ME_GetTableRowEnd(ME_DisplayItem *para) DECLSPEC_HIDDEN
Definition: table.c:136
int align(int length, int align)
Definition: dsound8.c:36
#define ITextHost_TxGetClientRect(This, a)
Definition: editor.h:308
static HRESULT shape_para(ME_Context *c, ME_DisplayItem *p)
Definition: wrap.c:847
int nCharOfs
Definition: editstr.h:166
#define PFM_LINESPACING
Definition: richedit.h:849
ME_Style * style
Definition: editstr.h:164
void ME_JoinRuns(ME_TextEditor *editor, ME_DisplayItem *p) DECLSPEC_HIDDEN
Definition: run.c:229
static void ME_PrepareParagraphForWrapping(ME_TextEditor *editor, ME_Context *c, ME_DisplayItem *tp)
Definition: wrap.c:730
#define PFE_RTLPARA
Definition: richedit.h:932
#define ITextHost_TxNotify(This, a, b)
Definition: editor.h:322
static void * heap_realloc(void *mem, size_t len)
Definition: appwiz.h:70
static void layout_row(ME_DisplayItem *start, const ME_DisplayItem *end)
Definition: wrap.c:236
static void * heap_alloc(size_t len)
Definition: appwiz.h:65
static BOOL get_run_glyph_buffers(ME_Run *run)
Definition: wrap.c:52
LONG dySpaceAfter
Definition: richedit.h:676
static ME_DisplayItem * ME_MakeRow(int height, int baseline, int width)
Definition: wrap.c:180
struct _test_info info[]
Definition: SetCursorPos.c:19
SCROLLINFO vert_si
Definition: editstr.h:443
#define MERF_TAB
Definition: editstr.h:111
ME_DisplayItem * ME_MakeDI(ME_DIType type) DECLSPEC_HIDDEN
Definition: list.c:178
void ls(int argc, const char *argv[])
Definition: cmds.c:1136
WORD wNumbering
Definition: richedit.h:668
ME_String * text
Definition: editstr.h:209
POINT pt
Definition: editstr.h:456
static void calc_run_extent(ME_Context *c, const ME_Paragraph *para, int startx, ME_Run *run)
Definition: wrap.c:115
static const char * debugstr_run(const ME_Run *run)
Definition: editor.h:46
static void ME_WrapEndParagraph(ME_WrapContext *wc, ME_DisplayItem *p)
Definition: wrap.c:384
BOOL bOverflown
Definition: wrap.c:45
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
#define MERF_ENDWHITE
Definition: editstr.h:122
WORD wNumberingTab
Definition: richedit.h:680
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
struct tagME_DisplayItem * next
Definition: editstr.h:261
#define MERF_HIDDEN
Definition: editstr.h:130
void select_style(ME_Context *c, ME_Style *s) DECLSPEC_HIDDEN
Definition: style.c:369
unsigned int BOOL
Definition: ntddk_ex.h:94
static void adjust_para_y(ME_DisplayItem *item, ME_Context *c, ME_DisplayItem *repaint_start, ME_DisplayItem *repaint_end)
Definition: wrap.c:979
void para_num_init(ME_Context *c, ME_Paragraph *para) DECLSPEC_HIDDEN
Definition: para.c:395
#define FIXME(fmt,...)
Definition: debug.h:110
int nParaNumOffset
Definition: wrap.c:41
void ME_DestroyDisplayItem(ME_DisplayItem *item) DECLSPEC_HIDDEN
Definition: list.c:160
#define pp
Definition: hlsl.yy.c:1208
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
POINT pt
Definition: wrap.c:44
#define MERF_ENDPARA
Definition: editstr.h:126
ME_TextBuffer * pBuffer
Definition: editstr.h:390
void remove_marked_para(ME_TextEditor *editor, ME_DisplayItem *para) DECLSPEC_HIDDEN
Definition: para.c:82
LONG dxStartIndent
Definition: richedit.h:670
int nDescent
Definition: editstr.h:170
smooth NULL
Definition: ftsmooth.c:416
Definition: editstr.h:91
LONG cx
Definition: windef.h:334
int len
Definition: editstr.h:167
void ME_InitContext(ME_Context *c, ME_TextEditor *editor, HDC hDC)
Definition: context.c:23
LONG dxRightIndent
Definition: richedit.h:671
int nAvailWidth
Definition: editstr.h:459
#define PFE_TABLE
Definition: richedit.h:944
static int find_non_whitespace(const WCHAR *s, int len, int start)
Definition: wrap.c:424
DWORD dwMask
Definition: richedit.h:667
#define ITextHost_TxGetDC(This)
Definition: editor.h:287
static void ME_WrapSizeRun(ME_WrapContext *wc, ME_DisplayItem *p)
Definition: wrap.c:413
int nLen
Definition: editstr.h:61
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
_In_ uint64_t _In_ uint64_t _In_ uint64_t _In_opt_ traverse_ptr * tp
Definition: btrfs.c:2855
void ME_InvalidateParagraphRange(ME_TextEditor *editor, ME_DisplayItem *start_para, ME_DisplayItem *last_para)
Definition: wrap.c:1168
void ME_SendRequestResize(ME_TextEditor *editor, BOOL force)
Definition: wrap.c:1198
int nAvailWidth
Definition: wrap.c:42
int ME_GetParaBorderWidth(const ME_Context *c, int flags) DECLSPEC_HIDDEN
Definition: paint.c:529
#define TRACE(s)
Definition: solgame.cpp:4
static void ME_BeginRow(ME_WrapContext *wc)
Definition: wrap.c:190
GLsizeiptr size
Definition: glext.h:5919
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define MERF_WHITESPACE
Definition: editstr.h:124
GOFFSET * offsets
Definition: editstr.h:179
LONG HRESULT
Definition: typedefs.h:77
WINE_DEFAULT_DEBUG_CHANNEL(richedit)
#define MERF_SPLITTABLE
Definition: editstr.h:118
#define PFA_CENTER
Definition: richedit.h:923
void ME_InsertBefore(ME_DisplayItem *diWhere, ME_DisplayItem *diWhat) DECLSPEC_HIDDEN
Definition: list.c:26
GLint GLint GLsizei GLsizei GLsizei GLint border
Definition: gl.h:1546
const GLubyte * c
Definition: glext.h:8905
static HRESULT shape_run(ME_Context *c, ME_Run *run)
Definition: wrap.c:65
unsigned short WORD
Definition: ntddk_ex.h:93
int nRightMargin
Definition: wrap.c:39
BOOL ME_CanJoinRuns(const ME_Run *run1, const ME_Run *run2) DECLSPEC_HIDDEN
Definition: run.c:35
void ME_Remove(ME_DisplayItem *diWhere) DECLSPEC_HIDDEN
Definition: list.c:35
void ME_DestroyContext(ME_Context *c)
Definition: context.c:44
int nLeftMargin
Definition: wrap.c:39
int nFlags
Definition: editstr.h:169
ME_BorderRect border
Definition: editstr.h:229
#define MEPF_ROWSTART
Definition: editstr.h:148
#define MEPF_REWRAP
Definition: editstr.h:145
ITextHost * texthost
Definition: editstr.h:387
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
#define PFM_TABLE
Definition: richedit.h:870
int nRightBoundary
Definition: editstr.h:228
int nWidth
Definition: editstr.h:168
static int state
Definition: maze.c:121
GLenum GLsizei len
Definition: glext.h:6722
Definition: editstr.h:90
unsigned char BYTE
Definition: mem.h:68
LONG dyLineSpacing
Definition: richedit.h:676
GLdouble s
Definition: gl.h:2039
static WCHAR * get_text(const ME_Run *run, int offset)
Definition: editor.h:41
static ME_DisplayItem * ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
Definition: wrap.c:577
ME_DisplayItem * pLast
Definition: editstr.h:272
int nFirstMargin
Definition: wrap.c:40
POINT pt
Definition: editstr.h:171
int get_total_width(ME_TextEditor *editor) DECLSPEC_HIDDEN
Definition: para.c:64
ME_Style * style
Definition: wrap.c:37
SCRIPT_CACHE script_cache
Definition: editstr.h:82
ME_Cell cell
Definition: editstr.h:265
GLint GLint GLsizei GLsizei height
Definition: gl.h:1546
int * advances
Definition: editstr.h:178
WORD wEffects
Definition: richedit.h:669
#define ERR(fmt,...)
Definition: debug.h:109
BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor)
Definition: wrap.c:1093
ME_Border bottom
Definition: editstr.h:194
static ATOM item
Definition: dde.c:856
const char cursor[]
Definition: icontest.c:13
BOOL bEmulateVersion10
Definition: editstr.h:389
static void ME_WrapTextParagraph(ME_TextEditor *editor, ME_Context *c, ME_DisplayItem *tp)
Definition: wrap.c:868
static int ME_IsWSpace(WCHAR ch)
Definition: editor.h:101
PARAFORMAT2 fmt
Definition: editstr.h:208
struct para_num para_num
Definition: editstr.h:219
GLuint start
Definition: gl.h:1545
ME_DisplayItem * pPara
Definition: wrap.c:46
#define ARRAY_SIZE(a)
Definition: main.h:24
static void ME_MarkRepaintEnd(ME_DisplayItem *para, ME_DisplayItem **repaint_start, ME_DisplayItem **repaint_end)
Definition: wrap.c:970
WORD wBorders
Definition: richedit.h:681
struct define * next
Definition: compiler.c:65
#define MERF_ENDROW
Definition: editstr.h:128
static ME_DisplayItem * split_run_extents(ME_WrapContext *wc, ME_DisplayItem *item, int nVChar)
Definition: wrap.c:131
int num_glyphs
Definition: editstr.h:175
int nHeight
Definition: editstr.h:231
ME_DisplayItem * pRowStart
Definition: wrap.c:47
int nLastTotalLength
Definition: editstr.h:396
#define ENM_REQUESTRESIZE
Definition: richedit.h:477
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
int yTextOffset
Definition: editstr.h:232
struct tagME_DisplayItem * next_para
Definition: editstr.h:221
int ME_twips2pointsY(const ME_Context *c, int y) DECLSPEC_HIDDEN
Definition: paint.c:161
LONG dySpaceBefore
Definition: richedit.h:676
void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run) DECLSPEC_HIDDEN
Definition: run.c:413
SCRIPT_ANALYSIS script_analysis
Definition: editstr.h:174
int max_clusters
Definition: editstr.h:180
WORD * glyphs
Definition: editstr.h:176
static ME_DisplayItem * ME_MaximizeSplit(ME_WrapContext *wc, ME_DisplayItem *p, int i)
Definition: wrap.c:456
ME_DisplayItem * first_marked_para
Definition: editstr.h:437
_Out_opt_ int * cx
Definition: commctrl.h:581
struct tagME_DisplayItem * next_cell
Definition: editstr.h:233
int nWidth
Definition: editstr.h:231
#define c
Definition: ke_i.h:80
#define MEPF_COMPLEX
Definition: editstr.h:150
ME_DisplayItem * ME_FindItemFwd(ME_DisplayItem *di, ME_DIType nTypeOrClass) DECLSPEC_HIDDEN
Definition: list.c:134
BYTE bLineSpacingRule
Definition: richedit.h:678
LONG bottom
Definition: windef.h:309
static const WCHAR sp[]
Definition: suminfo.c:288
int ME_PointFromCharContext(ME_Context *c, ME_Run *pRun, int nOffset, BOOL visual_order) DECLSPEC_HIDDEN
Definition: run.c:557
struct tagME_WrapContext ME_WrapContext
#define EN_REQUESTRESIZE
Definition: richedit.h:192
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
GLfloat GLfloat p
Definition: glext.h:8902
BOOL bWordWrap
Definition: wrap.c:45
static TCHAR * items[]
Definition: page1.c:45
LONG dxOffset
Definition: richedit.h:672
#define TRACE_ON(x)
Definition: compat.h:65
LONG cy
Definition: windef.h:335
SCRIPT_VISATTR * vis_attrs
Definition: editstr.h:177
struct tagME_DisplayItem * prev
Definition: editstr.h:261
int nAscent
Definition: editstr.h:170
ME_DisplayItem * ME_FindItemBack(ME_DisplayItem *di, ME_DIType nTypeOrClass) DECLSPEC_HIDDEN
Definition: list.c:111
union tagME_DisplayItem::@521 member
#define LANG_USER_DEFAULT
Definition: tnerror.cpp:50
#define SUCCEEDED(hr)
Definition: intsafe.h:57
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
int max_glyphs
Definition: editstr.h:175
static BOOL heap_free(void *mem)
Definition: appwiz.h:75
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
int ME_CharFromPointContext(ME_Context *c, int cx, ME_Run *run, BOOL closest, BOOL visual_order) DECLSPEC_HIDDEN
Definition: run.c:462
struct tagME_DisplayItem * prev_cell
Definition: editstr.h:233
int ME_twips2pointsX(const ME_Context *c, int x) DECLSPEC_HIDDEN
Definition: paint.c:153