ReactOS  0.4.14-dev-604-gcfdd483
text.c
Go to the documentation of this file.
1 /*
2  * ReactOS kernel
3  * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /*
20  * PROJECT: ReactOS user32.dll
21  * FILE: win32ss/user/rtl/text.c
22  * PURPOSE: Draw Text
23  * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
24  * UPDATE HISTORY:
25  * 09-05-2001 CSH Created
26  */
27 
28 /* INCLUDES ******************************************************************/
29 
30 #ifdef _WIN32K_
31 #include <win32k.h>
32 DBG_DEFAULT_CHANNEL(UserMenu);
33 #else
34 #include <user32.h>
35 #include <wine/debug.h>
37 #endif
38 
39 /* FUNCTIONS *****************************************************************/
40 
41 #ifndef NDEBUG
42 
43 #ifdef assert
44 #undef assert
45 #endif
46 
47 #define assert(e) ((e) ? (void)0 : _font_assert(#e, __FILE__, __LINE__))
48 
49 #else
50 #include <assert.h>
51 
52 #endif
53 
54 void _font_assert(const char *msg, const char *file, int line)
55 {
56  /* Assertion failed at foo.c line 45: x<y */
57  DbgPrint("Assertion failed at %s line %d: %s\n", file, line, msg);
58 #ifdef _WIN32K_
59  ASSERT(FALSE);
60 #else
61  ExitProcess(3);
62  for(;;); /* eliminate warning by mingw */
63 #endif
64 }
65 
66 /*********************************************************************
67  *
68  * DrawText functions
69  *
70  * Copied from Wine.
71  * Copyright 1993, 1994 Alexandre Julliard
72  * Copyright 2002 Bill Medland
73  *
74  * Design issues
75  * How many buffers to use
76  * While processing in DrawText there are potentially three different forms
77  * of the text that need to be held. How are they best held?
78  * 1. The original text is needed, of course, to see what to display.
79  * 2. The text that will be returned to the user if the DT_MODIFYSTRING is
80  * in effect.
81  * 3. The buffered text that is about to be displayed e.g. the current line.
82  * Typically this will exclude the ampersands used for prefixing etc.
83  *
84  * Complications.
85  * a. If the buffered text to be displayed includes the ampersands then
86  * we will need special measurement and draw functions that will ignore
87  * the ampersands (e.g. by copying to a buffer without the prefix and
88  * then using the normal forms). This may involve less space but may
89  * require more processing. e.g. since a line containing tabs may
90  * contain several underlined characters either we need to carry around
91  * a list of prefix locations or we may need to locate them several
92  * times.
93  * b. If we actually directly modify the "original text" as we go then we
94  * will need some special "caching" to handle the fact that when we
95  * ellipsify the text the ellipsis may modify the next line of text,
96  * which we have not yet processed. (e.g. ellipsification of a W at the
97  * end of a line will overwrite the W, the \n and the first character of
98  * the next line, and a \0 will overwrite the second. Try it!!)
99  *
100  * Option 1. Three separate storages. (To be implemented)
101  * If DT_MODIFYSTRING is in effect then allocate an extra buffer to hold
102  * the edited string in some form, either as the string itself or as some
103  * sort of "edit list" to be applied just before returning.
104  * Use a buffer that holds the ellipsified current line sans ampersands
105  * and accept the need occasionally to recalculate the prefixes (if
106  * DT_EXPANDTABS and not DT_NOPREFIX and not DT_HIDEPREFIX)
107  */
108 
109 #define TAB 9
110 #define LF 10
111 #define CR 13
112 #define SPACE 32
113 #define PREFIX 38
114 #define ALPHA_PREFIX 30 /* Win16: Alphabet prefix */
115 #define KANA_PREFIX 31 /* Win16: Katakana prefix */
116 
117 #define FORWARD_SLASH '/'
118 #define BACK_SLASH '\\'
119 
120 static const WCHAR ELLIPSISW[] = {'.','.','.', 0};
121 
122 typedef struct tag_ellipsis_data
123 {
124  int before;
125  int len;
126  int under;
127  int after;
128 } ellipsis_data;
129 
130 /*********************************************************************
131  * TEXT_Ellipsify (static)
132  *
133  * Add an ellipsis to the end of the given string whilst ensuring it fits.
134  *
135  * If the ellipsis alone doesn't fit then it will be returned anyway.
136  *
137  * See Also TEXT_PathEllipsify
138  *
139  * Arguments
140  * hdc [in] The handle to the DC that defines the font.
141  * str [in/out] The string that needs to be modified.
142  * max_str [in] The dimension of str (number of WCHAR).
143  * len_str [in/out] The number of characters in str
144  * width [in] The maximum width permitted (in logical coordinates)
145  * size [out] The dimensions of the text
146  * modstr [out] The modified form of the string, to be returned to the
147  * calling program. It is assumed that the caller has
148  * made sufficient space available so we don't need to
149  * know the size of the space. This pointer may be NULL if
150  * the modified string is not required.
151  * len_before [out] The number of characters before the ellipsis.
152  * len_ellip [out] The number of characters in the ellipsis.
153  *
154  * See for example Microsoft article Q249678.
155  *
156  * For now we will simply use three dots rather than worrying about whether
157  * the font contains an explicit ellipsis character.
158  */
159 static void TEXT_Ellipsify (HDC hdc, WCHAR *str, unsigned int max_len,
160  unsigned int *len_str, int width, SIZE *size,
161  WCHAR *modstr,
162  int *len_before, int *len_ellip)
163 {
164  unsigned int len_ellipsis;
165  unsigned int lo, mid, hi;
166  len_ellipsis = strlenW (ELLIPSISW);
167  if (len_ellipsis > max_len) len_ellipsis = max_len;
168  if (*len_str > max_len - len_ellipsis)
169  *len_str = max_len - len_ellipsis;
170 
171  /* First do a quick binary search to get an upper bound for *len_str. */
172  if (*len_str > 0 &&
173 #ifdef _WIN32K_
174  GreGetTextExtentExW(hdc, str, *len_str, width, NULL, NULL, size, 0) &&
175 #else
176  GetTextExtentExPointW(hdc, str, *len_str, width, NULL, NULL, size) &&
177 #endif
178  size->cx > width)
179  {
180  for (lo = 0, hi = *len_str; lo < hi; )
181  {
182  mid = (lo + hi) / 2;
183 #ifdef _WIN32K_
184  if (!GreGetTextExtentExW(hdc, str, mid, width, NULL, NULL, size, 0))
185 #else
186  if (!GetTextExtentExPointW(hdc, str, mid, width, NULL, NULL, size))
187 #endif
188  break;
189  if (size->cx > width)
190  hi = mid;
191  else
192  lo = mid + 1;
193  }
194  *len_str = hi;
195  }
196  /* Now this should take only a couple iterations at most. */
197  for ( ; ; )
198  {
199  memcpy(str + *len_str, ELLIPSISW, len_ellipsis*sizeof(WCHAR));
200 #ifdef _WIN32K_
201  if (!GreGetTextExtentExW (hdc, str, *len_str + len_ellipsis, width,
202  NULL, NULL, size, 0)) break;
203 #else
204  if (!GetTextExtentExPointW (hdc, str, *len_str + len_ellipsis, width,
205  NULL, NULL, size)) break;
206 #endif
207  if (!*len_str || size->cx <= width) break;
208 
209  (*len_str)--;
210  }
211  *len_ellip = len_ellipsis;
212  *len_before = *len_str;
213  *len_str += len_ellipsis;
214 
215  if (modstr)
216  {
217  memcpy (modstr, str, *len_str * sizeof(WCHAR));
218  modstr[*len_str] = '\0';
219  }
220 }
221 
222 /*********************************************************************
223  * TEXT_PathEllipsify (static)
224  *
225  * Add an ellipsis to the provided string in order to make it fit within
226  * the width. The ellipsis is added as specified for the DT_PATH_ELLIPSIS
227  * flag.
228  *
229  * See Also TEXT_Ellipsify
230  *
231  * Arguments
232  * hdc [in] The handle to the DC that defines the font.
233  * str [in/out] The string that needs to be modified
234  * max_str [in] The dimension of str (number of WCHAR).
235  * len_str [in/out] The number of characters in str
236  * width [in] The maximum width permitted (in logical coordinates)
237  * size [out] The dimensions of the text
238  * modstr [out] The modified form of the string, to be returned to the
239  * calling program. It is assumed that the caller has
240  * made sufficient space available so we don't need to
241  * know the size of the space. This pointer may be NULL if
242  * the modified string is not required.
243  * pellip [out] The ellipsification results
244  *
245  * For now we will simply use three dots rather than worrying about whether
246  * the font contains an explicit ellipsis character.
247  *
248  * The following applies, I think to Win95. We will need to extend it for
249  * Win98 which can have both path and end ellipsis at the same time (e.g.
250  * C:\MyLongFileName.Txt becomes ...\MyLongFileN...)
251  *
252  * The resulting string consists of as much as possible of the following:
253  * 1. The ellipsis itself
254  * 2. The last \ or / of the string (if any)
255  * 3. Everything after the last \ or / of the string (if any) or the whole
256  * string if there is no / or \. I believe that under Win95 this would
257  * include everything even though some might be clipped off the end whereas
258  * under Win98 that might be ellipsified too.
259  * Yet to be investigated is whether this would include wordbreaking if the
260  * filename is more than 1 word and splitting if DT_EDITCONTROL was in
261  * effect. (If DT_EDITCONTROL is in effect then on occasions text will be
262  * broken within words).
263  * 4. All the stuff before the / or \, which is placed before the ellipsis.
264  */
265 static void TEXT_PathEllipsify (HDC hdc, WCHAR *str, unsigned int max_len,
266  unsigned int *len_str, int width, SIZE *size,
267  WCHAR *modstr, ellipsis_data *pellip)
268 {
269  int len_ellipsis;
270  int len_trailing;
271  int len_under;
272  WCHAR *lastBkSlash, *lastFwdSlash, *lastSlash;
273  len_ellipsis = strlenW (ELLIPSISW);
274  if (!max_len) return;
275  if (len_ellipsis >= max_len) len_ellipsis = max_len - 1;
276  if (*len_str + len_ellipsis >= max_len)
277  *len_str = max_len - len_ellipsis-1;
278  /* Hopefully this will never happen, otherwise it would probably lose
279  * the wrong character
280  */
281  str[*len_str] = '\0'; /* to simplify things */
282 #ifdef _WIN32K_
283  lastBkSlash = wcsrchr (str, BACK_SLASH);
284  lastFwdSlash = wcsrchr (str, FORWARD_SLASH);
285 #else
286  lastBkSlash = strrchrW (str, BACK_SLASH);
287  lastFwdSlash = strrchrW (str, FORWARD_SLASH);
288 #endif
289  lastSlash = lastBkSlash > lastFwdSlash ? lastBkSlash : lastFwdSlash;
290  if (!lastSlash) lastSlash = str;
291  len_trailing = *len_str - (lastSlash - str);
292 
293  /* overlap-safe movement to the right */
294  memmove (lastSlash+len_ellipsis, lastSlash, len_trailing * sizeof(WCHAR));
295  memcpy (lastSlash, ELLIPSISW, len_ellipsis*sizeof(WCHAR));
296  len_trailing += len_ellipsis;
297  /* From this point on lastSlash actually points to the ellipsis in front
298  * of the last slash and len_trailing includes the ellipsis
299  */
300 
301  len_under = 0;
302  for ( ; ; )
303  {
304 #ifdef _WIN32K_
305  if (!GreGetTextExtentExW (hdc, str, *len_str + len_ellipsis, width,
306  NULL, NULL, size, 0)) break;
307 #else
308  if (!GetTextExtentExPointW (hdc, str, *len_str + len_ellipsis, width,
309  NULL, NULL, size)) break;
310 #endif
311  if (lastSlash == str || size->cx <= width) break;
312 
313  /* overlap-safe movement to the left */
314  memmove (lastSlash-1, lastSlash, len_trailing * sizeof(WCHAR));
315  lastSlash--;
316  len_under++;
317 
318  assert (*len_str);
319  (*len_str)--;
320  }
321  pellip->before = lastSlash-str;
322  pellip->len = len_ellipsis;
323  pellip->under = len_under;
324  pellip->after = len_trailing - len_ellipsis;
325  *len_str += len_ellipsis;
326 
327  if (modstr)
328  {
329  memcpy(modstr, str, *len_str * sizeof(WCHAR));
330  modstr[*len_str] = '\0';
331  }
332 }
333 
334 /* Check the character is Chinese, Japanese, Korean and/or Thai */
335 inline BOOL IsCJKT(WCHAR wch)
336 {
337  if (0x0E00 <= wch && wch <= 0x0E7F)
338  return TRUE; /* Thai */
339 
340  if (0x3000 <= wch && wch <= 0x9FFF)
341  return TRUE; /* CJK */
342 
343  if (0xAC00 <= wch && wch <= 0xD7FF)
344  return TRUE; /* Korean */
345 
346  if (0xFF00 <= wch && wch <= 0xFFEF)
347  return TRUE; /* CJK */
348 
349  return FALSE;
350 }
351 
352 /* See http://en.wikipedia.org/wiki/Kinsoku_shori */
353 static const WCHAR KinsokuClassA[] =
354 {
355  0x2010, 0x2013, 0x2019, 0x201D, 0x203C, 0x2047, 0x2048, 0x2049, 0x3001,
356  0x3002, 0x3005, 0x3009, 0x300B, 0x300D, 0x300F, 0x3011, 0x3015, 0x3017,
357  0x3019, 0x301C, 0x301F, 0x303B, 0x3041, 0x3043, 0x3045, 0x3047, 0x3049,
358  0x3063, 0x3083, 0x3085, 0x3087, 0x308E, 0x3095, 0x3096, 0x30A0, 0x30A1,
359  0x30A3, 0x30A5, 0x30A7, 0x30A9, 0x30C3, 0x30E3, 0x30E5, 0x30E7, 0x30EE,
360  0x30F5, 0x30F6, 0x30FB, 0x30FC, 0x30FD, 0x30FE, 0x31F0, 0x31F1, 0x31F2,
361  0x31F3, 0x31F4, 0x31F5, 0x31F6, 0x31F7, 0x31F8, 0x31F9, 0x31FA, 0x31FB,
362  0x31FC, 0x31FD, 0x31FE, 0x31FF, 0xFF01, 0xFF09, 0xFF0C, 0xFF0E, 0xFF1A,
363  0xFF1B, 0xFF1F, 0xFF3D, 0xFF5D, 0xFF60, 0
364 };
365 
366 /*********************************************************************
367  * TEXT_WordBreak (static)
368  *
369  * Perform wordbreak processing on the given string
370  *
371  * Assumes that DT_WORDBREAK has been specified and not all the characters
372  * fit. Note that this function should even be called when the first character
373  * that doesn't fit is known to be a space or tab, so that it can swallow them.
374  *
375  * Note that the Windows processing has some strange properties.
376  * 1. If the text is left-justified and there is room for some of the spaces
377  * that follow the last word on the line then those that fit are included on
378  * the line.
379  * 2. If the text is centred or right-justified and there is room for some of
380  * the spaces that follow the last word on the line then all but one of those
381  * that fit are included on the line.
382  * 3. (Reasonable behaviour) If the word breaking causes a space to be the first
383  * character of a new line it will be skipped.
384  *
385  * Arguments
386  * hdc [in] The handle to the DC that defines the font.
387  * str [in/out] The string that needs to be broken.
388  * max_str [in] The dimension of str (number of WCHAR).
389  * len_str [in/out] The number of characters in str
390  * width [in] The maximum width permitted
391  * format [in] The format flags in effect
392  * chars_fit [in] The maximum number of characters of str that are already
393  * known to fit; chars_fit+1 is known not to fit.
394  * chars_used [out] The number of characters of str that have been "used" and
395  * do not need to be included in later text. For example this will
396  * include any spaces that have been discarded from the start of
397  * the next line.
398  * size [out] The size of the returned text in logical coordinates
399  *
400  * Pedantic assumption - Assumes that the text length is monotonically
401  * increasing with number of characters (i.e. no weird kernings)
402  *
403  * Algorithm
404  *
405  * Work back from the last character that did fit to either a space or the last
406  * character of a word, whichever is met first.
407  * If there was one or the first character didn't fit then
408  * If the text is centred or right justified and that one character was a
409  * space then break the line before that character
410  * Otherwise break the line after that character
411  * and if the next character is a space then discard it.
412  * Suppose there was none (and the first character did fit).
413  * If Break Within Word is permitted
414  * break the word after the last character that fits (there must be
415  * at least one; none is caught earlier).
416  * Otherwise
417  * discard any trailing space.
418  * include the whole word; it may be ellipsified later
419  *
420  * Break Within Word is permitted under a set of circumstances that are not
421  * totally clear yet. Currently our best guess is:
422  * If DT_EDITCONTROL is in effect and neither DT_WORD_ELLIPSIS nor
423  * DT_PATH_ELLIPSIS is
424  */
425 
426 static void TEXT_WordBreak (HDC hdc, WCHAR *str, unsigned int max_str,
427  unsigned int *len_str,
428  int width, int format, unsigned int chars_fit,
429  unsigned int *chars_used, SIZE *size)
430 {
431  WCHAR *p;
432  int word_fits;
434  assert (chars_fit < *len_str);
435 
436  /* Work back from the last character that did fit to either a space or the
437  * last character of a word, whichever is met first.
438  */
439  p = str + chars_fit; /* The character that doesn't fit */
440  word_fits = TRUE;
441  if (!chars_fit)
442  word_fits = FALSE;
443  else if (*p == SPACE) /* chars_fit < *len_str so this is valid */
444  p--; /* the word just fitted */
445  else
446  {
447  while (p > str && *(--p) != SPACE && (!IsCJKT(p[1]) ||
448  p[1] == L'\0' || wcschr(KinsokuClassA, p[1]) != NULL))
449  ;
450  word_fits = (p != str || *p == SPACE || IsCJKT(p[1]));
451  }
452  /* If there was one. */
453  if (word_fits)
454  {
455  int next_is_space;
456  /* break the line before/after that character */
457  if (!(format & (DT_RIGHT | DT_CENTER)) || *p != SPACE)
458  p++;
459  next_is_space = (unsigned int) (p - str) < *len_str && *p == SPACE;
460  *len_str = p - str;
461  /* and if the next character is a space then discard it. */
462  *chars_used = *len_str;
463  if (next_is_space)
464  (*chars_used)++;
465  }
466  /* Suppose there was none. */
467  else
468  {
471  {
472  /* break the word after the last character that fits (there must be
473  * at least one). */
474  if (!chars_fit)
475  ++chars_fit;
476  *len_str = chars_fit;
477  *chars_used = chars_fit;
478 
479  /* FIXME - possible error. Since the next character is now removed
480  * this could make the text longer so that it no longer fits, and
481  * so we need a loop to test and shrink.
482  */
483  }
484  /* Otherwise */
485  else
486  {
487  /* discard any trailing space. */
488  const WCHAR *e = str + *len_str;
489  p = str + chars_fit;
490  while (p < e && *p != SPACE)
491  p++;
492  *chars_used = p - str;
493  if (p < e) /* i.e. loop failed because *p == SPACE */
494  (*chars_used)++;
495 
496  /* include the whole word; it may be ellipsified later */
497  *len_str = p - str;
498  /* Possible optimisation; if DT_WORD_ELLIPSIS only use chars_fit+1
499  * so that it will be too long
500  */
501  }
502  }
503  /* Remeasure the string */
504 #ifdef _WIN32K_
505  GreGetTextExtentExW (hdc, str, *len_str, 0, NULL, NULL, size, 0);
506 #else
507  GetTextExtentExPointW (hdc, str, *len_str, 0, NULL, NULL, size);
508 #endif
509 }
510 
511 /*********************************************************************
512  * TEXT_SkipChars
513  *
514  * Skip over the given number of characters, bearing in mind prefix
515  * substitution and the fact that a character may take more than one
516  * WCHAR (Unicode surrogates are two words long) (and there may have been
517  * a trailing &)
518  *
519  * Parameters
520  * new_count [out] The updated count
521  * new_str [out] The updated pointer
522  * start_count [in] The count of remaining characters corresponding to the
523  * start of the string
524  * start_str [in] The starting point of the string
525  * max [in] The number of characters actually in this segment of the
526  * string (the & counts)
527  * n [in] The number of characters to skip (if prefix then
528  * &c counts as one)
529  * prefix [in] Apply prefix substitution
530  *
531  * Return Values
532  * none
533  *
534  * Remarks
535  * There must be at least n characters in the string
536  * We need max because the "line" may have ended with a & followed by a tab
537  * or newline etc. which we don't want to swallow
538  */
539 
540 static void TEXT_SkipChars (int *new_count, const WCHAR **new_str,
541  int start_count, const WCHAR *start_str,
542  int max, int n, int prefix)
543 {
544  /* This is specific to wide characters, MSDN doesn't say anything much
545  * about Unicode surrogates yet and it isn't clear if _wcsinc will
546  * correctly handle them so we'll just do this the easy way for now
547  */
548 
549  if (prefix)
550  {
551  const WCHAR *str_on_entry = start_str;
552  assert (max >= n);
553  max -= n;
554  while (n--)
555  {
556  if ((*start_str == PREFIX || *start_str == ALPHA_PREFIX) && max--)
557  start_str++;
558  start_str++;
559  }
560  start_count -= (start_str - str_on_entry);
561  }
562  else
563  {
564  start_str += n;
565  start_count -= n;
566  }
567  *new_str = start_str;
568  *new_count = start_count;
569 }
570 
571 /*********************************************************************
572  * TEXT_Reprefix
573  *
574  * Reanalyse the text to find the prefixed character. This is called when
575  * wordbreaking or ellipsification has shortened the string such that the
576  * previously noted prefixed character is no longer visible.
577  *
578  * Parameters
579  * str [in] The original string segment (including all characters)
580  * ns [in] The number of characters in str (including prefixes)
581  * pe [in] The ellipsification data
582  *
583  * Return Values
584  * The prefix offset within the new string segment (the one that contains the
585  * ellipses and does not contain the prefix characters) (-1 if none)
586  */
587 
588 static int TEXT_Reprefix (const WCHAR *str, unsigned int ns,
589  const ellipsis_data *pe)
590 {
591  int result = -1;
592  unsigned int i;
593  unsigned int n = pe->before + pe->under + pe->after;
594  assert (n <= ns);
595  for (i = 0; i < n; i++, str++)
596  {
597  if (i == (unsigned int) pe->before)
598  {
599  /* Reached the path ellipsis; jump over it */
600  if (ns < (unsigned int) pe->under) break;
601  str += pe->under;
602  ns -= pe->under;
603  i += pe->under;
604  if (!pe->after) break; /* Nothing after the path ellipsis */
605  }
606  if (!ns) break;
607  ns--;
608  if (*str++ == PREFIX || *str == ALPHA_PREFIX)
609  {
610  str++;
611  if (!ns) break;
612  if (*str != PREFIX)
613  result = (i < (unsigned int) pe->before || pe->under == 0) ? i : i - pe->under + pe->len;
614  /* pe->len may be non-zero while pe_under is zero */
615  ns--;
616  }
617  }
618  return result;
619 }
620 
621 /*********************************************************************
622  * Returns true if and only if the remainder of the line is a single
623  * newline representation or nothing
624  */
625 
626 static int remainder_is_none_or_newline (int num_chars, const WCHAR *str)
627 {
628  if (!num_chars) return TRUE;
629  if (*str != LF && *str != CR) return FALSE;
630  if (!--num_chars) return TRUE;
631  if (*str == *(str+1)) return FALSE;
632  str++;
633  if (*str != CR && *str != LF) return FALSE;
634  if (--num_chars) return FALSE;
635  return TRUE;
636 }
637 
638 /*********************************************************************
639  * Return next line of text from a string.
640  *
641  * hdc - handle to DC.
642  * str - string to parse into lines.
643  * count - length of str.
644  * dest - destination in which to return line.
645  * len - dest buffer size in chars on input, copied length into dest on output.
646  * width - maximum width of line in pixels.
647  * format - format type passed to DrawText.
648  * retsize - returned size of the line in pixels.
649  * last_line - TRUE if is the last line that will be processed
650  * p_retstr - If DT_MODIFYSTRING this points to a cursor in the buffer in which
651  * the return string is built.
652  * tabwidth - The width of a tab in logical coordinates
653  * pprefix_offset - Here is where we return the offset within dest of the first
654  * prefixed (underlined) character. -1 is returned if there
655  * are none. Note that there may be more; the calling code
656  * will need to use TEXT_Reprefix to find any later ones.
657  * pellip - Here is where we return the information about any ellipsification
658  * that was carried out. Note that if tabs are being expanded then
659  * this data will correspond to the last text segment actually
660  * returned in dest; by definition there would not have been any
661  * ellipsification in earlier text segments of the line.
662  *
663  * Returns pointer to next char in str after end of the line
664  * or NULL if end of str reached.
665  */
666 static const WCHAR *TEXT_NextLineW( HDC hdc, const WCHAR *str, int *count,
667  WCHAR *dest, int *len, int width, DWORD format,
668  SIZE *retsize, int last_line, WCHAR **p_retstr,
669  int tabwidth, int *pprefix_offset,
670  ellipsis_data *pellip)
671 {
672  int i = 0, j = 0;
673  int plen = 0;
674  SIZE size = {0, 0};
675  int maxl = *len;
676  int seg_i, seg_count, seg_j;
677  int max_seg_width;
678  int num_fit;
679  int word_broken;
680  int line_fits;
681  unsigned int j_in_seg;
682  int ellipsified;
683  *pprefix_offset = -1;
684 
685  /* For each text segment in the line */
686 
687  retsize->cy = 0;
688  while (*count)
689  {
690 
691  /* Skip any leading tabs */
692 
693  if (str[i] == TAB && (format & DT_EXPANDTABS))
694  {
695  plen = ((plen/tabwidth)+1)*tabwidth;
696  (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++;
697  while (*count && str[i] == TAB)
698  {
699  plen += tabwidth;
700  (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++;
701  }
702  }
703 
704 
705  /* Now copy as far as the next tab or cr/lf or eos */
706 
707  seg_i = i;
708  seg_count = *count;
709  seg_j = j;
710 
711  while (*count &&
712  (str[i] != TAB || !(format & DT_EXPANDTABS)) &&
713  ((str[i] != CR && str[i] != LF) || (format & DT_SINGLELINE)))
714  {
715  if ((format & DT_NOPREFIX) || *count <= 1)
716  {
717  (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++;
718  continue;
719  }
720 
721  if (str[i] == PREFIX || str[i] == ALPHA_PREFIX) {
722  (*count)--, i++; /* Throw away the prefix itself */
723  if (str[i] == PREFIX)
724  {
725  /* Swallow it before we see it again */
726  (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++;
727  }
728  else if (*pprefix_offset == -1 || *pprefix_offset >= seg_j)
729  {
730  *pprefix_offset = j;
731  }
732  /* else the previous prefix was in an earlier segment of the
733  * line; we will leave it to the drawing code to catch this
734  * one.
735  */
736  }
737  else if (str[i] == KANA_PREFIX)
738  {
739  /* Throw away katakana access keys */
740  (*count)--, i++; /* skip the prefix */
741  (*count)--, i++; /* skip the letter */
742  }
743  else
744  {
745  (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++;
746  }
747  }
748 
749 
750  /* Measure the whole text segment and possibly WordBreak and
751  * ellipsify it
752  */
753 
754  j_in_seg = j - seg_j;
755  max_seg_width = width - plen;
756 #ifdef _WIN32K_
757  GreGetTextExtentExW (hdc, dest + seg_j, j_in_seg, max_seg_width, (PULONG)&num_fit, NULL, &size, 0);
758 #else
759  GetTextExtentExPointW (hdc, dest + seg_j, j_in_seg, max_seg_width, &num_fit, NULL, &size);
760 #endif
761 
762  /* The Microsoft handling of various combinations of formats is weird.
763  * The following may very easily be incorrect if several formats are
764  * combined, and may differ between versions (to say nothing of the
765  * several bugs in the Microsoft versions).
766  */
767  word_broken = 0;
768  line_fits = (num_fit >= j_in_seg);
769  if (!line_fits && (format & DT_WORDBREAK))
770  {
771  const WCHAR *s;
772  unsigned int chars_used;
773  TEXT_WordBreak (hdc, dest+seg_j, maxl-seg_j, &j_in_seg,
774  max_seg_width, format, num_fit, &chars_used, &size);
775  line_fits = (size.cx <= max_seg_width);
776  /* and correct the counts */
777  TEXT_SkipChars (count, &s, seg_count, str+seg_i, i-seg_i,
778  chars_used, !(format & DT_NOPREFIX));
779  i = s - str;
780  word_broken = 1;
781  }
782  pellip->before = j_in_seg;
783  pellip->under = 0;
784  pellip->after = 0;
785  pellip->len = 0;
786  ellipsified = 0;
787  if (!line_fits && (format & DT_PATH_ELLIPSIS))
788  {
789  TEXT_PathEllipsify (hdc, dest + seg_j, maxl-seg_j, &j_in_seg,
790  max_seg_width, &size, *p_retstr, pellip);
791  line_fits = (size.cx <= max_seg_width);
792  ellipsified = 1;
793  }
794  /* NB we may end up ellipsifying a word-broken or path_ellipsified
795  * string */
796  if ((!line_fits && (format & DT_WORD_ELLIPSIS)) ||
797  ((format & DT_END_ELLIPSIS) &&
798  ((last_line && *count) ||
799  (remainder_is_none_or_newline (*count, &str[i]) && !line_fits))))
800  {
801  int before, len_ellipsis;
802  TEXT_Ellipsify (hdc, dest + seg_j, maxl-seg_j, &j_in_seg,
803  max_seg_width, &size, *p_retstr, &before, &len_ellipsis);
804  if (before > pellip->before)
805  {
806  /* We must have done a path ellipsis too */
807  pellip->after = before - pellip->before - pellip->len;
808  /* Leave the len as the length of the first ellipsis */
809  }
810  else
811  {
812  /* If we are here after a path ellipsification it must be
813  * because even the ellipsis itself didn't fit.
814  */
815  assert (pellip->under == 0 && pellip->after == 0);
816  pellip->before = before;
817  pellip->len = len_ellipsis;
818  /* pellip->after remains as zero as does
819  * pellip->under
820  */
821  }
822  line_fits = (size.cx <= max_seg_width);
823  ellipsified = 1;
824  }
825  /* As an optimisation if we have ellipsified and we are expanding
826  * tabs and we haven't reached the end of the line we can skip to it
827  * now rather than going around the loop again.
828  */
829  if ((format & DT_EXPANDTABS) && ellipsified)
830  {
831  if (format & DT_SINGLELINE)
832  *count = 0;
833  else
834  {
835  while ((*count) && str[i] != CR && str[i] != LF)
836  {
837  (*count)--, i++;
838  }
839  }
840  }
841 
842  j = seg_j + j_in_seg;
843  if (*pprefix_offset >= seg_j + pellip->before)
844  {
845  *pprefix_offset = TEXT_Reprefix (str + seg_i, i - seg_i, pellip);
846  if (*pprefix_offset != -1)
847  *pprefix_offset += seg_j;
848  }
849 
850  plen += size.cx;
851  if (size.cy > retsize->cy)
852  retsize->cy = size.cy;
853 
854  if (word_broken)
855  break;
856  else if (!*count)
857  break;
858  else if (str[i] == CR || str[i] == LF)
859  {
860  (*count)--, i++;
861  if (*count && (str[i] == CR || str[i] == LF) && str[i] != str[i-1])
862  {
863  (*count)--, i++;
864  }
865  break;
866  }
867  /* else it was a Tab and we go around again */
868  }
869 
870  retsize->cx = plen;
871  *len = j;
872  if (*count)
873  return (&str[i]);
874  else
875  return NULL;
876 }
877 
878 
879 /***********************************************************************
880  * TEXT_DrawUnderscore
881  *
882  * Draw the underline under the prefixed character
883  *
884  * Parameters
885  * hdc [in] The handle of the DC for drawing
886  * x [in] The x location of the line segment (logical coordinates)
887  * y [in] The y location of where the underscore should appear
888  * (logical coordinates)
889  * str [in] The text of the line segment
890  * offset [in] The offset of the underscored character within str
891  * rect [in] Clipping rectangle (if not NULL)
892  */
893 /* Synced with wine 1.1.32 */
894 static void TEXT_DrawUnderscore (HDC hdc, int x, int y, const WCHAR *str, int offset, const RECT *rect)
895 {
896  int prefix_x;
897  int prefix_end;
898  SIZE size;
899  HPEN hpen;
900  HPEN oldPen;
901 #ifdef _WIN32K_
903 #else
905 #endif
906  prefix_x = x + size.cx;
907 #ifdef _WIN32K_
908  GreGetTextExtentW (hdc, str, offset+1, &size, 0);
909 #else
911 #endif
912  prefix_end = x + size.cx - 1;
913  /* The above method may eventually be slightly wrong due to kerning etc. */
914 
915  /* Check for clipping */
916  if (rect)
917  {
918  if (prefix_x > rect->right || prefix_end < rect->left ||
919  y < rect->top || y > rect->bottom)
920  return; /* Completely outside */
921  /* Partially outside */
922  if (prefix_x < rect->left ) prefix_x = rect->left;
923  if (prefix_end > rect->right) prefix_end = rect->right;
924  }
925 #ifdef _WIN32K_
927  oldPen = NtGdiSelectPen (hdc, hpen);
928  GreMoveTo (hdc, prefix_x, y, NULL);
929  NtGdiLineTo (hdc, prefix_end, y);
930  NtGdiSelectPen (hdc, oldPen);
932 #else
934  oldPen = SelectObject (hdc, hpen);
935  MoveToEx (hdc, prefix_x, y, NULL);
936  LineTo (hdc, prefix_end, y);
937  SelectObject (hdc, oldPen);
938  DeleteObject (hpen);
939 #endif
940 }
941 
942 #ifdef _WIN32K_
943 /***********************************************************************
944  * UserExtTextOutW
945  *
946  * Callback to usermode to use ExtTextOut, which will apply complex
947  * script processing if needed and then draw it
948  *
949  * Parameters
950  * hdc [in] The handle of the DC for drawing
951  * x [in] The x location of the string
952  * y [in] The y location of the string
953  * flags [in] ExtTextOut flags
954  * lprc [in] Clipping rectangle (if not NULL)
955  * lpString [in] String to be drawn
956  * count [in] String length
957  */
959  INT x,
960  INT y,
961  UINT flags,
962  PRECTL lprc,
963  LPCWSTR lpString,
964  UINT count)
965 {
966  PVOID ResultPointer;
968  ULONG ArgumentLength;
969  ULONG_PTR pStringBuffer;
971  PLPK_CALLBACK_ARGUMENTS Argument;
972  BOOL bResult;
973 
974  ArgumentLength = sizeof(LPK_CALLBACK_ARGUMENTS);
975 
976  pStringBuffer = ArgumentLength;
977  ArgumentLength += sizeof(WCHAR) * (count + 2);
978 
979  Argument = IntCbAllocateMemory(ArgumentLength);
980 
981  if (!Argument)
982  {
983  goto fallback;
984  }
985 
986  /* Initialize struct members */
987  Argument->hdc = hdc;
988  Argument->x = x;
989  Argument->y = y;
990  Argument->flags = flags;
991  Argument->count = count;
992 
993  if (lprc)
994  {
995  Argument->rect = *lprc;
996  Argument->bRect = TRUE;
997  }
998  else
999  {
1000  RtlZeroMemory(&Argument->rect, sizeof(RECT));
1001  Argument->bRect = FALSE;
1002  }
1003 
1004  /* Align lpString
1005  mimicks code from co_IntClientLoadLibrary */
1006  Argument->lpString = (LPWSTR)pStringBuffer;
1007  pStringBuffer += (ULONG_PTR)Argument;
1008 
1009  Status = RtlStringCchCopyNW((LPWSTR)pStringBuffer, count + 1, lpString, count);
1010 
1011  if (!NT_SUCCESS(Status))
1012  {
1013  IntCbFreeMemory(Argument);
1014  goto fallback;
1015  }
1016 
1017  UserLeaveCo();
1018 
1020  Argument,
1021  ArgumentLength,
1022  &ResultPointer,
1023  &ResultLength);
1024 
1025  UserEnterCo();
1026 
1027  IntCbFreeMemory(Argument);
1028 
1029  if (NT_SUCCESS(Status))
1030  {
1031  _SEH2_TRY
1032  {
1033  ProbeForRead(ResultPointer, sizeof(BOOL), 1);
1034  bResult = *(LPBOOL)ResultPointer;
1035  }
1037  {
1038  ERR("Failed to copy result from user mode!\n");
1040  }
1041  _SEH2_END;
1042  }
1043 
1044  if (!NT_SUCCESS(Status))
1045  {
1046  goto fallback;
1047  }
1048 
1049  return bResult;
1050 
1051 fallback:
1052  return GreExtTextOutW(hdc, x, y, flags, lprc, lpString, count, NULL, 0);
1053 }
1054 #endif
1055 
1056 /***********************************************************************
1057  * DrawTextExW (USER32.@)
1058  *
1059  * The documentation on the extra space required for DT_MODIFYSTRING at MSDN
1060  * is not quite complete, especially with regard to \0. We will assume that
1061  * the returned string could have a length of up to i_count+3 and also have
1062  * a trailing \0 (which would be 4 more than a not-null-terminated string but
1063  * 3 more than a null-terminated string). If this is not so then increase
1064  * the allowance in DrawTextExA.
1065  */
1066 #define MAX_BUFFER 1024
1067 /*
1068  * DrawTextExW
1069  *
1070  * Synced with Wine Staging 1.7.37
1071  */
1073  LPWSTR str,
1074  INT i_count,
1075  LPRECT rect,
1076  UINT flags,
1077  LPDRAWTEXTPARAMS dtp )
1078 {
1079  SIZE size;
1080  const WCHAR *strPtr;
1081  WCHAR *retstr, *p_retstr;
1082  size_t size_retstr;
1084  int len, lh, count=i_count;
1085  TEXTMETRICW tm;
1086  int lmargin = 0, rmargin = 0;
1087  int x = rect->left, y = rect->top;
1088  int width = rect->right - rect->left;
1089  int max_width = 0;
1090  int last_line;
1091  int tabwidth /* to keep gcc happy */ = 0;
1092  int prefix_offset;
1093  ellipsis_data ellip;
1094  BOOL invert_y=FALSE;
1095 
1096  HRGN hrgn = 0;
1097 
1098 #ifdef _WIN32K_
1099  TRACE("%S, %d, %08x\n", str, count, flags);
1100 #else
1101  TRACE("%s, %d, [%s] %08x\n", debugstr_wn (str, count), count,
1103 #endif
1104  if (dtp) TRACE("Params: iTabLength=%d, iLeftMargin=%d, iRightMargin=%d\n",
1105  dtp->iTabLength, dtp->iLeftMargin, dtp->iRightMargin);
1106 
1107  if (!str) return 0;
1108 
1109  strPtr = str;
1110 
1111  if (flags & DT_SINGLELINE)
1112  flags &= ~DT_WORDBREAK;
1113 #ifdef _WIN32K_
1115 #else
1116  GetTextMetricsW(hdc, &tm);
1117 #endif
1118  if (flags & DT_EXTERNALLEADING)
1119  lh = tm.tmHeight + tm.tmExternalLeading;
1120  else
1121  lh = tm.tmHeight;
1122 
1123  if (str[0] && count == 0)
1124  return lh;
1125 
1126  if (dtp && dtp->cbSize != sizeof(DRAWTEXTPARAMS))
1127  return 0;
1128 #ifdef _WIN32K_
1130  {
1131  SIZE window_ext, viewport_ext;
1132  GreGetWindowExtEx(hdc, &window_ext);
1133  GreGetViewportExtEx(hdc, &viewport_ext);
1134  if ((window_ext.cy > 0) != (viewport_ext.cy > 0))
1135  invert_y = TRUE;
1136  }
1137 #else
1139  {
1140  SIZE window_ext, viewport_ext;
1141  GetWindowExtEx(hdc, &window_ext);
1142  GetViewportExtEx(hdc, &viewport_ext);
1143  if ((window_ext.cy > 0) != (viewport_ext.cy > 0))
1144  invert_y = TRUE;
1145  }
1146 #endif
1147  if (count == -1)
1148  {
1149 #ifdef _WIN32K_
1150  count = wcslen(str);
1151 #else
1152  count = strlenW(str);
1153 #endif
1154  if (count == 0)
1155  {
1156  if( flags & DT_CALCRECT)
1157  {
1158  rect->right = rect->left;
1159  if( flags & DT_SINGLELINE)
1160  rect->bottom = rect->top + (invert_y ? -lh : lh);
1161  else
1162  rect->bottom = rect->top;
1163  }
1164  return lh;
1165  }
1166  }
1167 
1168  if (dtp)
1169  {
1170  lmargin = dtp->iLeftMargin;
1171  rmargin = dtp->iRightMargin;
1172  if (!(flags & (DT_CENTER | DT_RIGHT)))
1173  x += lmargin;
1174  dtp->uiLengthDrawn = 0; /* This param RECEIVES number of chars processed */
1175  }
1176 
1177  if (flags & DT_EXPANDTABS)
1178  {
1179  int tabstop = ((flags & DT_TABSTOP) && dtp && dtp->iTabLength) ? dtp->iTabLength : 8;
1180  tabwidth = tm.tmAveCharWidth * tabstop;
1181  }
1182 
1183  if (flags & DT_CALCRECT) flags |= DT_NOCLIP;
1184 #ifndef _WIN32K_
1185  if (!(flags & DT_NOCLIP) )
1186  {
1187  int hasClip;
1188  hrgn = CreateRectRgn(0,0,0,0);
1189  if (hrgn)
1190  {
1191  hasClip = GetClipRgn(hdc, hrgn);
1192  // If the region to be retrieved is NULL, the return value is 0.
1193  if (hasClip != 1)
1194  {
1195  DeleteObject(hrgn);
1196  hrgn = NULL;
1197  }
1198  IntersectClipRect(hdc, rect->left, rect->top, rect->right, rect->bottom);
1199  }
1200  }
1201 #else
1202  if (!(flags & DT_NOCLIP) )
1203  {
1204  int hasClip;
1205  hrgn = NtGdiCreateRectRgn(0,0,0,0);
1206  if (hrgn)
1207  {
1208  hasClip = NtGdiGetRandomRgn(hdc, hrgn, CLIPRGN);
1209  if (hasClip != 1)
1210  {
1212  hrgn = NULL;
1213  }
1214  NtGdiIntersectClipRect(hdc, rect->left, rect->top, rect->right, rect->bottom);
1215  }
1216  }
1217 #endif
1218  if (flags & DT_MODIFYSTRING)
1219  {
1220  size_retstr = (count + 4) * sizeof (WCHAR);
1221 #ifdef _WIN32K_
1222  retstr = ExAllocatePoolWithTag(PagedPool, size_retstr, USERTAG_RTL);
1223 #else
1224  retstr = HeapAlloc(GetProcessHeap(), 0, size_retstr);
1225 #endif
1226  if (!retstr) return 0;
1227  memcpy (retstr, str, size_retstr);
1228  }
1229  else
1230  {
1231  size_retstr = 0;
1232  retstr = NULL;
1233  }
1234  p_retstr = retstr;
1235 
1236  do
1237  {
1238  len = sizeof(line)/sizeof(line[0]);
1239  if (invert_y)
1240  last_line = !(flags & DT_NOCLIP) && y - ((flags & DT_EDITCONTROL) ? 2*lh-1 : lh) < rect->bottom;
1241  else
1242  last_line = !(flags & DT_NOCLIP) && y + ((flags & DT_EDITCONTROL) ? 2*lh-1 : lh) > rect->bottom;
1243  strPtr = TEXT_NextLineW(hdc, strPtr, &count, line, &len, width, flags, &size, last_line, &p_retstr, tabwidth, &prefix_offset, &ellip);
1244 
1245 #ifdef __REACTOS__
1246  if (flags & DT_CENTER)
1247  {
1248  if (((rect->right - rect->left) < size.cx) && (flags & DT_CALCRECT))
1249  {
1250  x = rect->left + size.cx;
1251  }
1252  else
1253  {
1254  x = (rect->left + rect->right - size.cx) / 2;
1255  }
1256  }
1257 #else
1258  if (flags & DT_CENTER) x = (rect->left + rect->right -
1259  size.cx) / 2;
1260 #endif
1261  else if (flags & DT_RIGHT) x = rect->right - size.cx;
1262 
1263  if (flags & DT_SINGLELINE)
1264  {
1265 #ifdef __REACTOS__
1266  if (flags & DT_VCENTER) y = rect->top +
1267  (rect->bottom - rect->top + (invert_y ? size.cy : -size.cy)) / 2;
1268  else if (flags & DT_BOTTOM)
1269  y = rect->bottom + (invert_y ? 0 : -size.cy);
1270 #else
1271  if (flags & DT_VCENTER) y = rect->top +
1272  (rect->bottom - rect->top) / 2 - size.cy / 2;
1273  else if (flags & DT_BOTTOM) y = rect->bottom - size.cy;
1274 #endif
1275  }
1276 
1277  if (!(flags & DT_CALCRECT))
1278  {
1279  const WCHAR *str = line;
1280  int xseg = x;
1281  while (len)
1282  {
1283  int len_seg;
1284  SIZE size;
1285  if ((flags & DT_EXPANDTABS))
1286  {
1287  const WCHAR *p;
1288  p = str; while (p < str+len && *p != TAB) p++;
1289  len_seg = p - str;
1290  if (len_seg != len &&
1291 #ifdef _WIN32K_
1292  !GreGetTextExtentW(hdc, str, len_seg, &size, 0))
1293 #else
1294  !GetTextExtentPointW(hdc, str, len_seg, &size))
1295 #endif
1296  {
1297 #ifdef _WIN32K_
1298  ExFreePoolWithTag(retstr, USERTAG_RTL);
1299 #else
1300  HeapFree (GetProcessHeap(), 0, retstr);
1301 #endif
1302  return 0;
1303  }
1304  }
1305  else
1306  len_seg = len;
1307 #ifdef _WIN32K_
1308  if (!UserExtTextOutW( hdc, xseg, y,
1309  ((flags & DT_NOCLIP) ? 0 : ETO_CLIPPED) |
1310  ((flags & DT_RTLREADING) ? ETO_RTLREADING : 0),
1311  rect, str, len_seg))
1312 #else
1313  if (!ExtTextOutW( hdc, xseg, y,
1314  ((flags & DT_NOCLIP) ? 0 : ETO_CLIPPED) |
1315  ((flags & DT_RTLREADING) ? ETO_RTLREADING : 0),
1316  rect, str, len_seg, NULL ))
1317 #endif
1318  {
1319 #ifdef _WIN32K_
1320  ExFreePoolWithTag(retstr, USERTAG_RTL);
1321 #else
1322  HeapFree (GetProcessHeap(), 0, retstr);
1323 #endif
1324  return 0;
1325  }
1326  if (prefix_offset != -1 && prefix_offset < len_seg)
1327  {
1328  TEXT_DrawUnderscore (hdc, xseg, y + tm.tmAscent + 1, str, prefix_offset, (flags & DT_NOCLIP) ? NULL : rect);
1329  }
1330  len -= len_seg;
1331  str += len_seg;
1332  if (len)
1333  {
1334  assert ((flags & DT_EXPANDTABS) && *str == TAB);
1335  len--; str++;
1336  xseg += ((size.cx/tabwidth)+1)*tabwidth;
1337  if (prefix_offset != -1)
1338  {
1339  if (prefix_offset < len_seg)
1340  {
1341  /* We have just drawn an underscore; we ought to
1342  * figure out where the next one is. I am going
1343  * to leave it for now until I have a better model
1344  * for the line, which will make reprefixing easier.
1345  * This is where ellip would be used.
1346  */
1347  prefix_offset = -1;
1348  }
1349  else
1350  prefix_offset -= len_seg;
1351  }
1352  }
1353  }
1354  }
1355  else if (size.cx > max_width)
1356  max_width = size.cx;
1357 
1358  y += invert_y ? -lh : lh;
1359  if (dtp)
1360  dtp->uiLengthDrawn += len;
1361  }
1362  while (strPtr && !last_line);
1363 
1364 #ifndef _WIN32K_
1365  if (!(flags & DT_NOCLIP) )
1366  {
1367  SelectClipRgn(hdc, hrgn); // This should be NtGdiExtSelectClipRgn, but due to ReactOS build rules this option is next:
1368  GdiFlush(); // Flush the batch and level up! See CORE-16498.
1369  if (hrgn)
1370  {
1371  DeleteObject(hrgn);
1372  }
1373  }
1374 #else
1375  if (!(flags & DT_NOCLIP) )
1376  {
1378  if (hrgn)
1379  {
1381  }
1382  }
1383 #endif
1384 
1385  if (flags & DT_CALCRECT)
1386  {
1387  rect->right = rect->left + max_width;
1388  rect->bottom = y;
1389  if (dtp)
1390  rect->right += lmargin + rmargin;
1391  }
1392  if (retstr)
1393  {
1394  memcpy (str, retstr, size_retstr);
1395 #ifdef _WIN32K_
1396  ExFreePoolWithTag(retstr, USERTAG_RTL);
1397 #else
1398  HeapFree (GetProcessHeap(), 0, retstr);
1399 #endif
1400  }
1401  return y - rect->top;
1402 }
1403 
IN CINT OUT PVOID IN ULONG OUT PULONG ResultLength
Definition: conport.c:47
NTSTATUS NTAPI KeUserModeCallback(IN ULONG RoutineIndex, IN PVOID Argument, IN ULONG ArgumentLength, OUT PVOID *Result, OUT PULONG ResultLength)
Definition: stubs.c:100
BOOL IsCJKT(WCHAR wch)
Definition: text.c:335
__kernel_entry W32KAPI HRGN APIENTRY NtGdiCreateRectRgn(_In_ INT xLeft, _In_ INT yTop, _In_ INT xRight, _In_ INT yBottom)
#define DT_EXPANDTABS
Definition: winuser.h:532
INT WINAPI DrawTextExWorker(HDC hdc, LPWSTR str, INT i_count, LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp)
Definition: text.c:1072
GLint GLint GLsizei width
Definition: gl.h:1546
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
#define max(a, b)
Definition: svc.c:63
#define DT_TABSTOP
Definition: winuser.h:541
BOOL NTAPI GreDeleteObject(HGDIOBJ hobj)
Definition: gdiobj.c:1155
#define TRUE
Definition: types.h:120
static void TEXT_WordBreak(HDC hdc, WCHAR *str, unsigned int max_str, unsigned int *len_str, int width, int format, unsigned int chars_fit, unsigned int *chars_used, SIZE *size)
Definition: text.c:426
HPEN WINAPI CreatePen(_In_ int, _In_ int, _In_ COLORREF)
static void TEXT_DrawUnderscore(HDC hdc, int x, int y, const WCHAR *str, int offset, const RECT *rect)
Definition: text.c:894
#define DT_RTLREADING
Definition: winuser.h:539
_In_ int _Inout_ LPRECT lprc
Definition: winuser.h:4440
__kernel_entry W32KAPI INT APIENTRY NtGdiIntersectClipRect(_In_ HDC hdc, _In_ INT xLeft, _In_ INT yTop, _In_ INT xRight, _In_ INT yBottom)
Definition: cliprgn.c:503
WINE_UNICODE_INLINE unsigned int strlenW(const WCHAR *str)
Definition: unicode.h:212
int WINAPI SelectClipRgn(_In_ HDC, _In_opt_ HRGN)
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define DbgPrint
Definition: loader.c:25
#define LF
Definition: text.c:110
VOID FASTCALL IntCbFreeMemory(PVOID Data)
Definition: callback.c:49
__kernel_entry W32KAPI INT APIENTRY NtGdiExtSelectClipRgn(_In_ HDC hdc, _In_opt_ HRGN hrgn, _In_ INT iMode)
const WCHAR * text
Definition: package.c:1827
GLuint GLuint GLsizei count
Definition: gl.h:1545
#define DT_WORDBREAK
Definition: winuser.h:544
BOOL FASTCALL GreGetTextExtentW(HDC hDC, LPCWSTR lpwsz, INT cwc, LPSIZE psize, UINT flOpts)
Definition: text.c:36
LONG NTSTATUS
Definition: precomp.h:26
static HDC
Definition: imagelist.c:92
GLintptr offset
Definition: glext.h:5920
GLdouble n
Definition: glext.h:7729
int WINAPI IntersectClipRect(_In_ HDC, _In_ int, _In_ int, _In_ int, _In_ int)
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
Definition: dc.c:1497
VOID WINAPI ExitProcess(IN UINT uExitCode)
Definition: proc.c:1487
BOOL WINAPI GreGetViewportExtEx(_In_ HDC hdc, _Out_ LPSIZE lpSize)
Definition: coord.c:1413
BOOL WINAPI DeleteObject(_In_ HGDIOBJ)
BOOL WINAPI LineTo(_In_ HDC, _In_ int, _In_ int)
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
__inline int before(__u32 seq1, __u32 seq2)
Definition: tcpcore.h:2414
static HPEN hpen
#define DT_RIGHT
Definition: winuser.h:538
#define DT_NOPREFIX
Definition: winuser.h:537
#define SPACE
Definition: text.c:112
int32_t INT
Definition: typedefs.h:56
& rect
Definition: startmenu.cpp:1413
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
_SEH2_TRY
Definition: create.c:4250
uint32_t ULONG_PTR
Definition: typedefs.h:63
#define DT_PATH_ELLIPSIS
Definition: winuser.h:530
BOOL WINAPI MoveToEx(_In_ HDC, _In_ int, _In_ int, _Out_opt_ LPPOINT)
#define PS_SOLID
Definition: wingdi.h:585
__kernel_entry W32KAPI BOOL APIENTRY NtGdiLineTo(_In_ HDC hdc, _In_ INT x, _In_ INT y)
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
__kernel_entry W32KAPI HPEN APIENTRY NtGdiSelectPen(_In_ HDC hdc, _In_ HPEN hpen)
static void TEXT_PathEllipsify(HDC hdc, WCHAR *str, unsigned int max_len, unsigned int *len_str, int width, SIZE *size, WCHAR *modstr, ellipsis_data *pellip)
Definition: text.c:265
#define KANA_PREFIX
Definition: text.c:115
#define DT_CALCRECT
Definition: winuser.h:526
unsigned int BOOL
Definition: ntddk_ex.h:94
#define e
Definition: ke_i.h:82
#define UserLeaveCo
Definition: ntuser.h:10
#define TAB
Definition: text.c:109
BOOL WINAPI ExtTextOutW(_In_ HDC hdc, _In_ INT x, _In_ INT y, _In_ UINT fuOptions, _In_opt_ const RECT *lprc, _In_reads_opt_(cwc) LPCWSTR lpString, _In_ UINT cwc, _In_reads_opt_(cwc) const INT *lpDx)
Definition: text.c:484
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
const WCHAR * str
#define DT_END_ELLIPSIS
Definition: winuser.h:529
smooth NULL
Definition: ftsmooth.c:416
LONG cx
Definition: windef.h:334
Definition: parser.c:48
_Check_return_ _CRTIMP _CONST_RETURN wchar_t *__cdecl wcsrchr(_In_z_ const wchar_t *_Str, _In_ wchar_t _Ch)
#define assert(e)
Definition: text.c:47
#define ETO_CLIPPED
Definition: wingdi.h:647
#define DT_VCENTER
Definition: winuser.h:543
PVOID FASTCALL IntCbAllocateMemory(ULONG Size)
Definition: callback.c:27
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
HRGN WINAPI CreateRectRgn(_In_ int, _In_ int, _In_ int, _In_ int)
#define DT_WORD_ELLIPSIS
Definition: winuser.h:531
static const WCHAR KinsokuClassA[]
Definition: text.c:353
#define TRACE(s)
Definition: solgame.cpp:4
GLsizeiptr size
Definition: glext.h:5919
#define GetProcessHeap()
Definition: compat.h:403
WINE_DEFAULT_DEBUG_CHANNEL(metafile)
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
_CONST_RETURN wchar_t *__cdecl wcschr(_In_z_ const wchar_t *_Str, wchar_t _Ch)
if(!(yy_init))
Definition: macro.lex.yy.c:714
BOOL WINAPI GetViewportExtEx(_In_ HDC, _Out_ LPSIZE)
Definition: coord.c:351
BOOL WINAPI GreGetTextMetricsW(_In_ HDC hdc, _Out_ LPTEXTMETRICW lptm)
Definition: text.c:151
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
NTSTRSAFEAPI RtlStringCchCopyNW(_Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cchDest, _In_reads_or_z_(cchToCopy) STRSAFE_LPCWSTR pszSrc, _In_ size_t cchToCopy)
Definition: ntstrsafe.h:363
int WINAPI GetGraphicsMode(_In_ HDC)
BOOL WINAPI GetWindowExtEx(_In_ HDC, _Out_ LPSIZE)
Definition: coord.c:411
#define WINAPI
Definition: msvc.h:6
const char * wine_dbgstr_rect(const RECT *rect)
BOOL APIENTRY GreExtTextOutW(IN HDC hDC, IN INT XStart, IN INT YStart, IN UINT fuOptions, IN OPTIONAL PRECTL lprc, IN LPCWSTR String, IN INT Count, IN OPTIONAL LPINT Dx, IN DWORD dwCodePage)
Definition: freetype.c:6696
#define USER32_CALLBACK_LPK
Definition: callback.h:20
unsigned long DWORD
Definition: ntddk_ex.h:95
GLint left
Definition: glext.h:7726
#define CLIPRGN
Definition: precomp.h:18
int iRightMargin
Definition: winuser.h:3075
#define UserEnterCo
Definition: ntuser.h:9
struct tag_ellipsis_data ellipsis_data
GLbitfield flags
Definition: glext.h:7161
#define GM_COMPATIBLE
Definition: wingdi.h:863
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
BOOL UserExtTextOutW(HDC hdc, INT x, INT y, UINT flags, PRECTL lprc, LPCWSTR lpString, UINT count)
char line[200]
Definition: main.c:97
VOID NTAPI ProbeForRead(IN CONST VOID *Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:102
Definition: mxnamespace.c:44
static const WCHAR L[]
Definition: oid.c:1250
BOOL WINAPI GetTextMetricsW(_In_ HDC hdc, _Out_ LPTEXTMETRICW lptm)
Definition: text.c:221
HDC hdc
Definition: main.c:9
#define FORWARD_SLASH
Definition: text.c:117
static HRGN hrgn
Definition: win.c:55
static int remainder_is_none_or_newline(int num_chars, const WCHAR *str)
Definition: text.c:626
BOOL APIENTRY GetTextExtentPointW(_In_ HDC hdc, _In_reads_(cchString) LPCWSTR lpString, _In_ INT cchString, _Out_ LPSIZE lpsz)
Definition: text.c:268
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
GLdouble s
Definition: gl.h:2039
static void TEXT_Ellipsify(HDC hdc, WCHAR *str, unsigned int max_len, unsigned int *len_str, int width, SIZE *size, WCHAR *modstr, int *len_before, int *len_ellip)
Definition: text.c:159
#define BACK_SLASH
Definition: text.c:118
Definition: time.h:76
BOOL FASTCALL GreMoveTo(HDC hdc, INT x, INT y, LPPOINT pptOut)
Definition: line.c:108
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:102
static int TEXT_Reprefix(const WCHAR *str, unsigned int ns, const ellipsis_data *pe)
Definition: text.c:588
#define debugstr_wn
Definition: kernel32.h:33
Status
Definition: gdiplustypes.h:24
static const WCHAR * TEXT_NextLineW(HDC hdc, const WCHAR *str, int *count, WCHAR *dest, int *len, int width, DWORD format, SIZE *retsize, int last_line, WCHAR **p_retstr, int tabwidth, int *pprefix_offset, ellipsis_data *pellip)
Definition: text.c:666
#define RGN_COPY
Definition: wingdi.h:356
WINE_UNICODE_INLINE WCHAR * strrchrW(const WCHAR *str, WCHAR ch)
Definition: unicode.h:254
COLORREF WINAPI GetTextColor(_In_ HDC hdc)
Definition: text.c:831
#define CR
Definition: text.c:111
#define ERR(fmt,...)
Definition: debug.h:109
BOOL WINAPI GdiFlush(void)
Definition: misc.c:44
#define DT_NOCLIP
Definition: winuser.h:536
#define DT_SINGLELINE
Definition: winuser.h:540
static const WCHAR ELLIPSISW[]
Definition: text.c:120
_SEH2_END
Definition: create.c:4424
BOOL * LPBOOL
Definition: windef.h:162
__kernel_entry W32KAPI HPEN APIENTRY NtGdiCreatePen(_In_ INT iPenStyle, _In_ INT iPenWidth, _In_ COLORREF cr, _In_opt_ HBRUSH hbr)
#define DT_EXTERNALLEADING
Definition: winuser.h:533
#define ALPHA_PREFIX
Definition: text.c:114
struct _LPK_CALLBACK_ARGUMENTS LPK_CALLBACK_ARGUMENTS
BOOL WINAPI GreGetWindowExtEx(_In_ HDC hdc, _Out_ LPSIZE lpSize)
Definition: coord.c:1404
unsigned int * PULONG
Definition: retypes.h:1
unsigned int UINT
Definition: ndis.h:50
__kernel_entry W32KAPI INT APIENTRY NtGdiGetRandomRgn(_In_ HDC hdc, _In_ HRGN hrgn, _In_ INT iRgn)
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
#define PREFIX
Definition: text.c:113
COLORREF FASTCALL GreGetTextColor(HDC)
Definition: dcutil.c:80
void _font_assert(const char *msg, const char *file, int line)
Definition: text.c:54
#define msg(x)
Definition: auth_time.c:54
BOOL WINAPI GetTextExtentExPointW(_In_ HDC hdc, _In_reads_(cchString) LPCWSTR lpszString, _In_ INT cchString, _In_ INT nMaxExtent, _Out_opt_ LPINT lpnFit, _Out_writes_to_opt_(cchString, *lpnFit) LPINT lpnDx, _Out_ LPSIZE lpSize)
Definition: text.c:283
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define USERTAG_RTL
Definition: tags.h:269
#define ULONG_PTR
Definition: config.h:101
UINT uiLengthDrawn
Definition: winuser.h:3076
#define DT_CENTER
Definition: winuser.h:527
static char * dest
Definition: rtl.c:135
int WINAPI GetClipRgn(_In_ HDC, _In_ HRGN)
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
GLdouble GLdouble GLdouble GLdouble top
Definition: glext.h:10859
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
GLuint64EXT * result
Definition: glext.h:11304
#define DT_BOTTOM
Definition: winuser.h:525
LONG cy
Definition: windef.h:335
BOOL FASTCALL GreGetTextExtentExW(HDC hDC, LPCWSTR String, ULONG Count, ULONG MaxExtent, PULONG Fit, PULONG Dx, LPSIZE pSize, FLONG fl)
Definition: text.c:93
static void TEXT_SkipChars(int *new_count, const WCHAR **new_str, int start_count, const WCHAR *start_str, int max, int n, int prefix)
Definition: text.c:540
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define HeapFree(x, y, z)
Definition: compat.h:402
#define MAX_BUFFER
Definition: text.c:1066
#define DT_EDITCONTROL
Definition: winuser.h:528
int FASTCALL GreGetGraphicsMode(HDC)
Definition: dcutil.c:306
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
Definition: fci.c:126