3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
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.
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.
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.
20 * PROJECT: ReactOS user32.dll
21 * FILE: lib/user32/windows/input.c
23 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * 09-05-2001 CSH Created
28 /* INCLUDES ******************************************************************/
32 #include <wine/debug.h>
34 WINE_DEFAULT_DEBUG_CHANNEL(text
);
36 DWORD WINAPI
GdiGetCodePage(HDC hdc
);
39 /* FUNCTIONS *****************************************************************/
47 #define assert(e) ((e) ? (void)0 : _font_assert(#e, __FILE__, __LINE__))
51 void _font_assert(const char *msg
, const char *file
, int line
)
53 /* Assertion failed at foo.c line 45: x<y */
54 DbgPrint("Assertion failed at %s line %d: %s\n", file
, line
, msg
);
56 for(;;); /* eliminate warning by mingw */
71 CONST INT
*lpnTabStopPositions
,
77 UINT cp
= GdiGetCodePage( hDC
); // CP_ACP
79 len
= MultiByteToWideChar(cp
, 0, lpString
, nCount
, NULL
, 0);
81 strW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
83 MultiByteToWideChar(cp
, 0, lpString
, nCount
, strW
, len
);
84 ret
= TabbedTextOutW(hDC
, X
, Y
, strW
, len
, nTabPositions
, lpnTabStopPositions
, nTabOrigin
);
85 HeapFree(GetProcessHeap(), 0, strW
);
90 /***********************************************************************
93 * Helper function for TabbedTextOut() and GetTabbedTextExtent().
94 * Note: this doesn't work too well for text-alignment modes other
95 * than TA_LEFT|TA_TOP. But we want bug-for-bug compatibility :-)
97 /* WINE synced 22-May-2006 */
98 static LONG
TEXT_TabbedTextOut( HDC hdc
, INT x
, INT y
, LPCWSTR lpstr
,
99 INT count
, INT cTabStops
, const INT
*lpTabPos
, INT nTabOrg
,
112 defWidth
= *lpTabPos
;
118 GetTextMetricsA( hdc
, &tm
);
119 defWidth
= 8 * tm
.tmAveCharWidth
;
128 /* chop the string into substrings of 0 or more <tabs>
129 * possibly followed by 1 or more normal characters */
130 for (i
= 0; i
< count
; i
++)
131 if (lpstr
[i
] != '\t') break;
132 for (j
= i
; j
< count
; j
++)
133 if (lpstr
[j
] == '\t') break;
134 /* get the extent of the normal character part */
135 GetTextExtentPointW( hdc
, lpstr
+ i
, j
- i
, &extent
);
136 /* and if there is a <tab>, calculate its position */
138 /* get x coordinate for the drawing of this string */
139 for (; cTabStops
> i
; lpTabPos
++, cTabStops
--)
141 if( nTabOrg
+ abs( *lpTabPos
) > x
) {
142 if( lpTabPos
[ i
- 1] >= 0) {
143 /* a left aligned tab */
144 x
= nTabOrg
+ lpTabPos
[ i
-1] + extent
.cx
;
149 /* if tab pos is negative then text is right-aligned
150 * to tab stop meaning that the string extends to the
151 * left, so we must subtract the width of the string */
152 if (nTabOrg
- lpTabPos
[ i
- 1] - extent
.cx
> x
)
154 x
= nTabOrg
- lpTabPos
[ i
- 1];
161 /* if we have run out of tab stops and we have a valid default tab
162 * stop width then round x up to that width */
163 if ((cTabStops
<= i
) && (defWidth
> 0)) {
164 x0
= nTabOrg
+ ((x
- nTabOrg
) / defWidth
+ i
) * defWidth
;
166 } else if ((cTabStops
<= i
) && (defWidth
< 0)) {
167 x
= nTabOrg
+ ((x
- nTabOrg
+ extent
.cx
) / -defWidth
+ i
)
178 r
.bottom
= y
+ extent
.cy
;
179 ExtTextOutW( hdc
, x0
, y
, GetBkMode(hdc
) == OPAQUE
? ETO_OPAQUE
: 0,
180 &r
, lpstr
+ i
, j
- i
, NULL
);
185 return MAKELONG(x
- start
, extent
.cy
);
200 CONST INT
*lpnTabStopPositions
,
203 return TEXT_TabbedTextOut(hDC
, X
, Y
, lpString
, nCount
, nTabPositions
, lpnTabStopPositions
, nTabOrigin
, TRUE
);
206 /* WINE synced 22-May-2006 */
212 GetTabbedTextExtentA(
217 CONST INT
*lpnTabStopPositions
)
220 UINT cp
= GdiGetCodePage( hDC
); // CP_ACP
224 len
= MultiByteToWideChar(cp
, 0, lpString
, nCount
, NULL
, 0);
226 strW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
228 MultiByteToWideChar(cp
, 0, lpString
, nCount
, strW
, len
);
229 ret
= GetTabbedTextExtentW(hDC
, strW
, len
, nTabPositions
, lpnTabStopPositions
);
230 HeapFree(GetProcessHeap(), 0, strW
);
239 GetTabbedTextExtentW(
244 CONST INT
*lpnTabStopPositions
)
246 return TEXT_TabbedTextOut(hDC
, 0, 0, lpString
, nCount
, nTabPositions
, lpnTabStopPositions
, 0, FALSE
);
249 /*********************************************************************
254 * Copyright 1993, 1994 Alexandre Julliard
255 * Copyright 2002 Bill Medland
258 * How many buffers to use
259 * While processing in DrawText there are potentially three different forms
260 * of the text that need to be held. How are they best held?
261 * 1. The original text is needed, of course, to see what to display.
262 * 2. The text that will be returned to the user if the DT_MODIFYSTRING is
264 * 3. The buffered text that is about to be displayed e.g. the current line.
265 * Typically this will exclude the ampersands used for prefixing etc.
268 * a. If the buffered text to be displayed includes the ampersands then
269 * we will need special measurement and draw functions that will ignore
270 * the ampersands (e.g. by copying to a buffer without the prefix and
271 * then using the normal forms). This may involve less space but may
272 * require more processing. e.g. since a line containing tabs may
273 * contain several underlined characters either we need to carry around
274 * a list of prefix locations or we may need to locate them several
276 * b. If we actually directly modify the "original text" as we go then we
277 * will need some special "caching" to handle the fact that when we
278 * ellipsify the text the ellipsis may modify the next line of text,
279 * which we have not yet processed. (e.g. ellipsification of a W at the
280 * end of a line will overwrite the W, the \n and the first character of
281 * the next line, and a \0 will overwrite the second. Try it!!)
283 * Option 1. Three separate storages. (To be implemented)
284 * If DT_MODIFYSTRING is in effect then allocate an extra buffer to hold
285 * the edited string in some form, either as the string itself or as some
286 * sort of "edit list" to be applied just before returning.
287 * Use a buffer that holds the ellipsified current line sans ampersands
288 * and accept the need occasionally to recalculate the prefixes (if
289 * DT_EXPANDTABS and not DT_NOPREFIX and not DT_HIDEPREFIX)
297 #define ALPHA_PREFIX 30 /* Win16: Alphabet prefix */
298 #define KANA_PREFIX 31 /* Win16: Katakana prefix */
300 #define FORWARD_SLASH '/'
301 #define BACK_SLASH '\\'
303 static const WCHAR ELLIPSISW
[] = {'.','.','.', 0};
305 typedef struct tag_ellipsis_data
313 /*********************************************************************
314 * TEXT_Ellipsify (static)
316 * Add an ellipsis to the end of the given string whilst ensuring it fits.
318 * If the ellipsis alone doesn't fit then it will be returned anyway.
320 * See Also TEXT_PathEllipsify
323 * hdc [in] The handle to the DC that defines the font.
324 * str [in/out] The string that needs to be modified.
325 * max_str [in] The dimension of str (number of WCHAR).
326 * len_str [in/out] The number of characters in str
327 * width [in] The maximum width permitted (in logical coordinates)
328 * size [out] The dimensions of the text
329 * modstr [out] The modified form of the string, to be returned to the
330 * calling program. It is assumed that the caller has
331 * made sufficient space available so we don't need to
332 * know the size of the space. This pointer may be NULL if
333 * the modified string is not required.
334 * len_before [out] The number of characters before the ellipsis.
335 * len_ellip [out] The number of characters in the ellipsis.
337 * See for example Microsoft article Q249678.
339 * For now we will simply use three dots rather than worrying about whether
340 * the font contains an explicit ellipsis character.
342 static void TEXT_Ellipsify (HDC hdc
, WCHAR
*str
, unsigned int max_len
,
343 unsigned int *len_str
, int width
, SIZE
*size
,
345 int *len_before
, int *len_ellip
)
347 unsigned int len_ellipsis
;
348 unsigned int lo
, mid
, hi
;
350 len_ellipsis
= strlenW (ELLIPSISW
);
351 if (len_ellipsis
> max_len
) len_ellipsis
= max_len
;
352 if (*len_str
> max_len
- len_ellipsis
)
353 *len_str
= max_len
- len_ellipsis
;
355 /* First do a quick binary search to get an upper bound for *len_str. */
357 GetTextExtentExPointW(hdc
, str
, *len_str
, width
, NULL
, NULL
, size
) &&
360 for (lo
= 0, hi
= *len_str
; lo
< hi
; )
363 if (!GetTextExtentExPointW(hdc
, str
, mid
, width
, NULL
, NULL
, size
))
365 if (size
->cx
> width
)
372 /* Now this should take only a couple iterations at most. */
375 memcpy(str
+ *len_str
, ELLIPSISW
, len_ellipsis
*sizeof(WCHAR
));
377 if (!GetTextExtentExPointW (hdc
, str
, *len_str
+ len_ellipsis
, width
,
378 NULL
, NULL
, size
)) break;
380 if (!*len_str
|| size
->cx
<= width
) break;
384 *len_ellip
= len_ellipsis
;
385 *len_before
= *len_str
;
386 *len_str
+= len_ellipsis
;
390 memcpy (modstr
, str
, *len_str
* sizeof(WCHAR
));
391 modstr
[*len_str
] = '\0';
395 /*********************************************************************
396 * TEXT_PathEllipsify (static)
398 * Add an ellipsis to the provided string in order to make it fit within
399 * the width. The ellipsis is added as specified for the DT_PATH_ELLIPSIS
402 * See Also TEXT_Ellipsify
405 * hdc [in] The handle to the DC that defines the font.
406 * str [in/out] The string that needs to be modified
407 * max_str [in] The dimension of str (number of WCHAR).
408 * len_str [in/out] The number of characters in str
409 * width [in] The maximum width permitted (in logical coordinates)
410 * size [out] The dimensions of the text
411 * modstr [out] The modified form of the string, to be returned to the
412 * calling program. It is assumed that the caller has
413 * made sufficient space available so we don't need to
414 * know the size of the space. This pointer may be NULL if
415 * the modified string is not required.
416 * pellip [out] The ellipsification results
418 * For now we will simply use three dots rather than worrying about whether
419 * the font contains an explicit ellipsis character.
421 * The following applies, I think to Win95. We will need to extend it for
422 * Win98 which can have both path and end ellipsis at the same time (e.g.
423 * C:\MyLongFileName.Txt becomes ...\MyLongFileN...)
425 * The resulting string consists of as much as possible of the following:
426 * 1. The ellipsis itself
427 * 2. The last \ or / of the string (if any)
428 * 3. Everything after the last \ or / of the string (if any) or the whole
429 * string if there is no / or \. I believe that under Win95 this would
430 * include everything even though some might be clipped off the end whereas
431 * under Win98 that might be ellipsified too.
432 * Yet to be investigated is whether this would include wordbreaking if the
433 * filename is more than 1 word and splitting if DT_EDITCONTROL was in
434 * effect. (If DT_EDITCONTROL is in effect then on occasions text will be
435 * broken within words).
436 * 4. All the stuff before the / or \, which is placed before the ellipsis.
438 static void TEXT_PathEllipsify (HDC hdc
, WCHAR
*str
, unsigned int max_len
,
439 unsigned int *len_str
, int width
, SIZE
*size
,
440 WCHAR
*modstr
, ellipsis_data
*pellip
)
445 WCHAR
*lastBkSlash
, *lastFwdSlash
, *lastSlash
;
447 len_ellipsis
= strlenW (ELLIPSISW
);
448 if (!max_len
) return;
449 if (len_ellipsis
>= max_len
) len_ellipsis
= max_len
- 1;
450 if (*len_str
+ len_ellipsis
>= max_len
)
451 *len_str
= max_len
- len_ellipsis
-1;
452 /* Hopefully this will never happen, otherwise it would probably lose
453 * the wrong character
455 str
[*len_str
] = '\0'; /* to simplify things */
457 lastBkSlash
= strrchrW (str
, BACK_SLASH
);
458 lastFwdSlash
= strrchrW (str
, FORWARD_SLASH
);
459 lastSlash
= lastBkSlash
> lastFwdSlash
? lastBkSlash
: lastFwdSlash
;
460 if (!lastSlash
) lastSlash
= str
;
461 len_trailing
= *len_str
- (lastSlash
- str
);
463 /* overlap-safe movement to the right */
464 memmove (lastSlash
+len_ellipsis
, lastSlash
, len_trailing
* sizeof(WCHAR
));
465 memcpy (lastSlash
, ELLIPSISW
, len_ellipsis
*sizeof(WCHAR
));
466 len_trailing
+= len_ellipsis
;
467 /* From this point on lastSlash actually points to the ellipsis in front
468 * of the last slash and len_trailing includes the ellipsis
474 if (!GetTextExtentExPointW (hdc
, str
, *len_str
+ len_ellipsis
, width
,
475 NULL
, NULL
, size
)) break;
477 if (lastSlash
== str
|| size
->cx
<= width
) break;
479 /* overlap-safe movement to the left */
480 memmove (lastSlash
-1, lastSlash
, len_trailing
* sizeof(WCHAR
));
487 pellip
->before
= lastSlash
-str
;
488 pellip
->len
= len_ellipsis
;
489 pellip
->under
= len_under
;
490 pellip
->after
= len_trailing
- len_ellipsis
;
491 *len_str
+= len_ellipsis
;
495 memcpy(modstr
, str
, *len_str
* sizeof(WCHAR
));
496 modstr
[*len_str
] = '\0';
500 /* Check the character is Chinese, Japanese, Korean and/or Thai */
501 inline BOOL
IsCJKT(WCHAR wch
)
503 if (0x0E00 <= wch
&& wch
<= 0x0E7F)
504 return TRUE
; /* Thai */
506 if (0x3000 <= wch
&& wch
<= 0x9FFF)
507 return TRUE
; /* CJK */
509 if (0xAC00 <= wch
&& wch
<= 0xD7FF)
510 return TRUE
; /* Korean */
512 if (0xFF00 <= wch
&& wch
<= 0xFFEF)
513 return TRUE
; /* CJK */
518 /* See http://en.wikipedia.org/wiki/Kinsoku_shori */
519 static const WCHAR KinsokuClassA
[] =
521 0x2010, 0x2013, 0x2019, 0x201D, 0x203C, 0x2047, 0x2048, 0x2049, 0x3001,
522 0x3002, 0x3005, 0x3009, 0x300B, 0x300D, 0x300F, 0x3011, 0x3015, 0x3017,
523 0x3019, 0x301C, 0x301F, 0x303B, 0x3041, 0x3043, 0x3045, 0x3047, 0x3049,
524 0x3063, 0x3083, 0x3085, 0x3087, 0x308E, 0x3095, 0x3096, 0x30A0, 0x30A1,
525 0x30A3, 0x30A5, 0x30A7, 0x30A9, 0x30C3, 0x30E3, 0x30E5, 0x30E7, 0x30EE,
526 0x30F5, 0x30F6, 0x30FB, 0x30FC, 0x30FD, 0x30FE, 0x31F0, 0x31F1, 0x31F2,
527 0x31F3, 0x31F4, 0x31F5, 0x31F6, 0x31F7, 0x31F8, 0x31F9, 0x31FA, 0x31FB,
528 0x31FC, 0x31FD, 0x31FE, 0x31FF, 0xFF01, 0xFF09, 0xFF0C, 0xFF0E, 0xFF1A,
529 0xFF1B, 0xFF1F, 0xFF3D, 0xFF5D, 0xFF60, 0
532 /*********************************************************************
533 * TEXT_WordBreak (static)
535 * Perform wordbreak processing on the given string
537 * Assumes that DT_WORDBREAK has been specified and not all the characters
538 * fit. Note that this function should even be called when the first character
539 * that doesn't fit is known to be a space or tab, so that it can swallow them.
541 * Note that the Windows processing has some strange properties.
542 * 1. If the text is left-justified and there is room for some of the spaces
543 * that follow the last word on the line then those that fit are included on
545 * 2. If the text is centred or right-justified and there is room for some of
546 * the spaces that follow the last word on the line then all but one of those
547 * that fit are included on the line.
548 * 3. (Reasonable behaviour) If the word breaking causes a space to be the first
549 * character of a new line it will be skipped.
552 * hdc [in] The handle to the DC that defines the font.
553 * str [in/out] The string that needs to be broken.
554 * max_str [in] The dimension of str (number of WCHAR).
555 * len_str [in/out] The number of characters in str
556 * width [in] The maximum width permitted
557 * format [in] The format flags in effect
558 * chars_fit [in] The maximum number of characters of str that are already
559 * known to fit; chars_fit+1 is known not to fit.
560 * chars_used [out] The number of characters of str that have been "used" and
561 * do not need to be included in later text. For example this will
562 * include any spaces that have been discarded from the start of
564 * size [out] The size of the returned text in logical coordinates
566 * Pedantic assumption - Assumes that the text length is monotonically
567 * increasing with number of characters (i.e. no weird kernings)
571 * Work back from the last character that did fit to either a space or the last
572 * character of a word, whichever is met first.
573 * If there was one or the first character didn't fit then
574 * If the text is centred or right justified and that one character was a
575 * space then break the line before that character
576 * Otherwise break the line after that character
577 * and if the next character is a space then discard it.
578 * Suppose there was none (and the first character did fit).
579 * If Break Within Word is permitted
580 * break the word after the last character that fits (there must be
581 * at least one; none is caught earlier).
583 * discard any trailing space.
584 * include the whole word; it may be ellipsified later
586 * Break Within Word is permitted under a set of circumstances that are not
587 * totally clear yet. Currently our best guess is:
588 * If DT_EDITCONTROL is in effect and neither DT_WORD_ELLIPSIS nor
589 * DT_PATH_ELLIPSIS is
592 static void TEXT_WordBreak (HDC hdc
, WCHAR
*str
, unsigned int max_str
,
593 unsigned int *len_str
,
594 int width
, int format
, unsigned int chars_fit
,
595 unsigned int *chars_used
, SIZE
*size
)
599 assert (format
& DT_WORDBREAK
);
600 assert (chars_fit
< *len_str
);
602 /* Work back from the last character that did fit to either a space or the
603 * last character of a word, whichever is met first.
605 p
= str
+ chars_fit
; /* The character that doesn't fit */
609 else if (*p
== SPACE
) /* chars_fit < *len_str so this is valid */
610 p
--; /* the word just fitted */
613 while (p
> str
&& *(--p
) != SPACE
&& (!IsCJKT(p
[1]) ||
614 p
[1] == L
'\0' || wcschr(KinsokuClassA
, p
[1]) != NULL
))
616 word_fits
= (p
!= str
|| *p
== SPACE
|| IsCJKT(p
[1]));
618 /* If there was one. */
622 /* break the line before/after that character */
623 if (!(format
& (DT_RIGHT
| DT_CENTER
)) || *p
!= SPACE
)
625 next_is_space
= (unsigned int) (p
- str
) < *len_str
&& *p
== SPACE
;
627 /* and if the next character is a space then discard it. */
628 *chars_used
= *len_str
;
632 /* Suppose there was none. */
635 if ((format
& (DT_EDITCONTROL
| DT_WORD_ELLIPSIS
| DT_PATH_ELLIPSIS
)) ==
638 /* break the word after the last character that fits (there must be
639 * at least one; none is caught earlier).
641 *len_str
= chars_fit
;
642 *chars_used
= chars_fit
;
644 /* FIXME - possible error. Since the next character is now removed
645 * this could make the text longer so that it no longer fits, and
646 * so we need a loop to test and shrink.
652 /* discard any trailing space. */
653 const WCHAR
*e
= str
+ *len_str
;
655 while (p
< e
&& *p
!= SPACE
)
657 *chars_used
= p
- str
;
658 if (p
< e
) /* i.e. loop failed because *p == SPACE */
661 /* include the whole word; it may be ellipsified later */
663 /* Possible optimisation; if DT_WORD_ELLIPSIS only use chars_fit+1
664 * so that it will be too long
668 /* Remeasure the string */
669 GetTextExtentExPointW (hdc
, str
, *len_str
, 0, NULL
, NULL
, size
);
672 /*********************************************************************
675 * Skip over the given number of characters, bearing in mind prefix
676 * substitution and the fact that a character may take more than one
677 * WCHAR (Unicode surrogates are two words long) (and there may have been
681 * new_count [out] The updated count
682 * new_str [out] The updated pointer
683 * start_count [in] The count of remaining characters corresponding to the
684 * start of the string
685 * start_str [in] The starting point of the string
686 * max [in] The number of characters actually in this segment of the
687 * string (the & counts)
688 * n [in] The number of characters to skip (if prefix then
690 * prefix [in] Apply prefix substitution
696 * There must be at least n characters in the string
697 * We need max because the "line" may have ended with a & followed by a tab
698 * or newline etc. which we don't want to swallow
701 static void TEXT_SkipChars (int *new_count
, const WCHAR
**new_str
,
702 int start_count
, const WCHAR
*start_str
,
703 int max
, int n
, int prefix
)
705 /* This is specific to wide characters, MSDN doesn't say anything much
706 * about Unicode surrogates yet and it isn't clear if _wcsinc will
707 * correctly handle them so we'll just do this the easy way for now
712 const WCHAR
*str_on_entry
= start_str
;
717 if ((*start_str
== PREFIX
|| *start_str
== ALPHA_PREFIX
) && max
--)
721 start_count
-= (start_str
- str_on_entry
);
728 *new_str
= start_str
;
729 *new_count
= start_count
;
732 /*********************************************************************
735 * Reanalyse the text to find the prefixed character. This is called when
736 * wordbreaking or ellipsification has shortened the string such that the
737 * previously noted prefixed character is no longer visible.
740 * str [in] The original string segment (including all characters)
741 * ns [in] The number of characters in str (including prefixes)
742 * pe [in] The ellipsification data
745 * The prefix offset within the new string segment (the one that contains the
746 * ellipses and does not contain the prefix characters) (-1 if none)
749 static int TEXT_Reprefix (const WCHAR
*str
, unsigned int ns
,
750 const ellipsis_data
*pe
)
754 unsigned int n
= pe
->before
+ pe
->under
+ pe
->after
;
756 for (i
= 0; i
< n
; i
++, str
++)
758 if (i
== (unsigned int) pe
->before
)
760 /* Reached the path ellipsis; jump over it */
761 if (ns
< (unsigned int) pe
->under
) break;
765 if (!pe
->after
) break; /* Nothing after the path ellipsis */
769 if (*str
++ == PREFIX
|| *str
== ALPHA_PREFIX
)
774 result
= (i
< (unsigned int) pe
->before
|| pe
->under
== 0) ? i
: i
- pe
->under
+ pe
->len
;
775 /* pe->len may be non-zero while pe_under is zero */
782 /*********************************************************************
783 * Returns true if and only if the remainder of the line is a single
784 * newline representation or nothing
787 static int remainder_is_none_or_newline (int num_chars
, const WCHAR
*str
)
789 if (!num_chars
) return TRUE
;
790 if (*str
!= LF
&& *str
!= CR
) return FALSE
;
791 if (!--num_chars
) return TRUE
;
792 if (*str
== *(str
+1)) return FALSE
;
794 if (*str
!= CR
&& *str
!= LF
) return FALSE
;
795 if (--num_chars
) return FALSE
;
799 /*********************************************************************
800 * Return next line of text from a string.
802 * hdc - handle to DC.
803 * str - string to parse into lines.
804 * count - length of str.
805 * dest - destination in which to return line.
806 * len - dest buffer size in chars on input, copied length into dest on output.
807 * width - maximum width of line in pixels.
808 * format - format type passed to DrawText.
809 * retsize - returned size of the line in pixels.
810 * last_line - TRUE if is the last line that will be processed
811 * p_retstr - If DT_MODIFYSTRING this points to a cursor in the buffer in which
812 * the return string is built.
813 * tabwidth - The width of a tab in logical coordinates
814 * pprefix_offset - Here is where we return the offset within dest of the first
815 * prefixed (underlined) character. -1 is returned if there
816 * are none. Note that there may be more; the calling code
817 * will need to use TEXT_Reprefix to find any later ones.
818 * pellip - Here is where we return the information about any ellipsification
819 * that was carried out. Note that if tabs are being expanded then
820 * this data will correspond to the last text segment actually
821 * returned in dest; by definition there would not have been any
822 * ellipsification in earlier text segments of the line.
824 * Returns pointer to next char in str after end of the line
825 * or NULL if end of str reached.
827 static const WCHAR
*TEXT_NextLineW( HDC hdc
, const WCHAR
*str
, int *count
,
828 WCHAR
*dest
, int *len
, int width
, DWORD format
,
829 SIZE
*retsize
, int last_line
, WCHAR
**p_retstr
,
830 int tabwidth
, int *pprefix_offset
,
831 ellipsis_data
*pellip
)
837 int seg_i
, seg_count
, seg_j
;
842 unsigned int j_in_seg
;
844 *pprefix_offset
= -1;
846 /* For each text segment in the line */
852 /* Skip any leading tabs */
854 if (str
[i
] == TAB
&& (format
& DT_EXPANDTABS
))
856 plen
= ((plen
/tabwidth
)+1)*tabwidth
;
857 (*count
)--; if (j
< maxl
) dest
[j
++] = str
[i
++]; else i
++;
858 while (*count
&& str
[i
] == TAB
)
861 (*count
)--; if (j
< maxl
) dest
[j
++] = str
[i
++]; else i
++;
866 /* Now copy as far as the next tab or cr/lf or eos */
873 (str
[i
] != TAB
|| !(format
& DT_EXPANDTABS
)) &&
874 ((str
[i
] != CR
&& str
[i
] != LF
) || (format
& DT_SINGLELINE
)))
876 if ((format
& DT_NOPREFIX
) || *count
<= 1)
878 (*count
)--; if (j
< maxl
) dest
[j
++] = str
[i
++]; else i
++;
882 if (str
[i
] == PREFIX
|| str
[i
] == ALPHA_PREFIX
) {
883 (*count
)--, i
++; /* Throw away the prefix itself */
884 if (str
[i
] == PREFIX
)
886 /* Swallow it before we see it again */
887 (*count
)--; if (j
< maxl
) dest
[j
++] = str
[i
++]; else i
++;
889 else if (*pprefix_offset
== -1 || *pprefix_offset
>= seg_j
)
893 /* else the previous prefix was in an earlier segment of the
894 * line; we will leave it to the drawing code to catch this
898 else if (str
[i
] == KANA_PREFIX
)
900 /* Throw away katakana access keys */
901 (*count
)--, i
++; /* skip the prefix */
902 (*count
)--, i
++; /* skip the letter */
906 (*count
)--; if (j
< maxl
) dest
[j
++] = str
[i
++]; else i
++;
911 /* Measure the whole text segment and possibly WordBreak and
915 j_in_seg
= j
- seg_j
;
916 max_seg_width
= width
- plen
;
917 GetTextExtentExPointW (hdc
, dest
+ seg_j
, j_in_seg
, max_seg_width
, &num_fit
, NULL
, &size
);
919 /* The Microsoft handling of various combinations of formats is weird.
920 * The following may very easily be incorrect if several formats are
921 * combined, and may differ between versions (to say nothing of the
922 * several bugs in the Microsoft versions).
925 line_fits
= (num_fit
>= j_in_seg
);
926 if (!line_fits
&& (format
& DT_WORDBREAK
))
929 unsigned int chars_used
;
930 TEXT_WordBreak (hdc
, dest
+seg_j
, maxl
-seg_j
, &j_in_seg
,
931 max_seg_width
, format
, num_fit
, &chars_used
, &size
);
932 line_fits
= (size
.cx
<= max_seg_width
);
933 /* and correct the counts */
934 TEXT_SkipChars (count
, &s
, seg_count
, str
+seg_i
, i
-seg_i
,
935 chars_used
, !(format
& DT_NOPREFIX
));
939 pellip
->before
= j_in_seg
;
944 if (!line_fits
&& (format
& DT_PATH_ELLIPSIS
))
946 TEXT_PathEllipsify (hdc
, dest
+ seg_j
, maxl
-seg_j
, &j_in_seg
,
947 max_seg_width
, &size
, *p_retstr
, pellip
);
948 line_fits
= (size
.cx
<= max_seg_width
);
951 /* NB we may end up ellipsifying a word-broken or path_ellipsified
953 if ((!line_fits
&& (format
& DT_WORD_ELLIPSIS
)) ||
954 ((format
& DT_END_ELLIPSIS
) &&
955 ((last_line
&& *count
) ||
956 (remainder_is_none_or_newline (*count
, &str
[i
]) && !line_fits
))))
958 int before
, len_ellipsis
;
959 TEXT_Ellipsify (hdc
, dest
+ seg_j
, maxl
-seg_j
, &j_in_seg
,
960 max_seg_width
, &size
, *p_retstr
, &before
, &len_ellipsis
);
961 if (before
> pellip
->before
)
963 /* We must have done a path ellipsis too */
964 pellip
->after
= before
- pellip
->before
- pellip
->len
;
965 /* Leave the len as the length of the first ellipsis */
969 /* If we are here after a path ellipsification it must be
970 * because even the ellipsis itself didn't fit.
972 assert (pellip
->under
== 0 && pellip
->after
== 0);
973 pellip
->before
= before
;
974 pellip
->len
= len_ellipsis
;
975 /* pellip->after remains as zero as does
979 line_fits
= (size
.cx
<= max_seg_width
);
982 /* As an optimisation if we have ellipsified and we are expanding
983 * tabs and we haven't reached the end of the line we can skip to it
984 * now rather than going around the loop again.
986 if ((format
& DT_EXPANDTABS
) && ellipsified
)
988 if (format
& DT_SINGLELINE
)
992 while ((*count
) && str
[i
] != CR
&& str
[i
] != LF
)
999 j
= seg_j
+ j_in_seg
;
1000 if (*pprefix_offset
>= seg_j
+ pellip
->before
)
1002 *pprefix_offset
= TEXT_Reprefix (str
+ seg_i
, i
- seg_i
, pellip
);
1003 if (*pprefix_offset
!= -1)
1004 *pprefix_offset
+= seg_j
;
1008 if (size
.cy
> retsize
->cy
)
1009 retsize
->cy
= size
.cy
;
1015 else if (str
[i
] == CR
|| str
[i
] == LF
)
1018 if (*count
&& (str
[i
] == CR
|| str
[i
] == LF
) && str
[i
] != str
[i
-1])
1024 /* else it was a Tab and we go around again */
1036 /***********************************************************************
1037 * TEXT_DrawUnderscore
1039 * Draw the underline under the prefixed character
1042 * hdc [in] The handle of the DC for drawing
1043 * x [in] The x location of the line segment (logical coordinates)
1044 * y [in] The y location of where the underscore should appear
1045 * (logical coordinates)
1046 * str [in] The text of the line segment
1047 * offset [in] The offset of the underscored character within str
1048 * rect [in] Clipping rectangle (if not NULL)
1050 /* Synced with wine 1.1.32 */
1051 static void TEXT_DrawUnderscore (HDC hdc
, int x
, int y
, const WCHAR
*str
, int offset
, const RECT
*rect
)
1059 GetTextExtentPointW (hdc
, str
, offset
, &size
);
1060 prefix_x
= x
+ size
.cx
;
1061 GetTextExtentPointW (hdc
, str
, offset
+1, &size
);
1062 prefix_end
= x
+ size
.cx
- 1;
1063 /* The above method may eventually be slightly wrong due to kerning etc. */
1065 /* Check for clipping */
1068 if (prefix_x
> rect
->right
|| prefix_end
< rect
->left
||
1069 y
< rect
->top
|| y
> rect
->bottom
)
1070 return; /* Completely outside */
1071 /* Partially outside */
1072 if (prefix_x
< rect
->left
) prefix_x
= rect
->left
;
1073 if (prefix_end
> rect
->right
) prefix_end
= rect
->right
;
1076 hpen
= CreatePen (PS_SOLID
, 1, GetTextColor (hdc
));
1077 oldPen
= SelectObject (hdc
, hpen
);
1078 MoveToEx (hdc
, prefix_x
, y
, NULL
);
1079 LineTo (hdc
, prefix_end
, y
);
1080 SelectObject (hdc
, oldPen
);
1081 DeleteObject (hpen
);
1084 /***********************************************************************
1085 * DrawTextExW (USER32.@)
1087 * The documentation on the extra space required for DT_MODIFYSTRING at MSDN
1088 * is not quite complete, especially with regard to \0. We will assume that
1089 * the returned string could have a length of up to i_count+3 and also have
1090 * a trailing \0 (which would be 4 more than a not-null-terminated string but
1091 * 3 more than a null-terminated string). If this is not so then increase
1092 * the allowance in DrawTextExA.
1094 #define MAX_BUFFER 1024
1098 * Synced with wine 1.1.32
1100 INT WINAPI
DrawTextExW( HDC hdc
, LPWSTR str
, INT i_count
,
1101 LPRECT rect
, UINT flags
, LPDRAWTEXTPARAMS dtp
)
1104 const WCHAR
*strPtr
;
1105 WCHAR
*retstr
, *p_retstr
;
1107 WCHAR line
[MAX_BUFFER
];
1108 int len
, lh
, count
=i_count
;
1110 int lmargin
= 0, rmargin
= 0;
1111 int x
= rect
->left
, y
= rect
->top
;
1112 int width
= rect
->right
- rect
->left
;
1115 int tabwidth
/* to keep gcc happy */ = 0;
1117 ellipsis_data ellip
;
1120 TRACE("%s, %d, [%s] %08x\n", debugstr_wn (str
, count
), count
,
1121 wine_dbgstr_rect(rect
), flags
);
1123 if (dtp
) TRACE("Params: iTabLength=%d, iLeftMargin=%d, iRightMargin=%d\n",
1124 dtp
->iTabLength
, dtp
->iLeftMargin
, dtp
->iRightMargin
);
1130 if (flags
& DT_SINGLELINE
)
1131 flags
&= ~DT_WORDBREAK
;
1133 GetTextMetricsW(hdc
, &tm
);
1134 if (flags
& DT_EXTERNALLEADING
)
1135 lh
= tm
.tmHeight
+ tm
.tmExternalLeading
;
1139 if (str
[0] && count
== 0)
1142 if (dtp
&& dtp
->cbSize
!= sizeof(DRAWTEXTPARAMS
))
1147 count
= strlenW(str
);
1150 if( flags
& DT_CALCRECT
)
1152 rect
->right
= rect
->left
;
1153 if( flags
& DT_SINGLELINE
)
1154 rect
->bottom
= rect
->top
+ lh
;
1156 rect
->bottom
= rect
->top
;
1162 if (GetGraphicsMode(hdc
) == GM_COMPATIBLE
)
1164 SIZE window_ext
, viewport_ext
;
1165 GetWindowExtEx(hdc
, &window_ext
);
1166 GetViewportExtEx(hdc
, &viewport_ext
);
1167 if ((window_ext
.cy
> 0) != (viewport_ext
.cy
> 0))
1173 lmargin
= dtp
->iLeftMargin
;
1174 rmargin
= dtp
->iRightMargin
;
1175 if (!(flags
& (DT_CENTER
| DT_RIGHT
)))
1177 dtp
->uiLengthDrawn
= 0; /* This param RECEIVES number of chars processed */
1180 if (flags
& DT_EXPANDTABS
)
1182 int tabstop
= ((flags
& DT_TABSTOP
) && dtp
) ? dtp
->iTabLength
: 8;
1183 tabwidth
= tm
.tmAveCharWidth
* tabstop
;
1186 if (flags
& DT_CALCRECT
) flags
|= DT_NOCLIP
;
1188 if (flags
& DT_MODIFYSTRING
)
1190 size_retstr
= (count
+ 4) * sizeof (WCHAR
);
1191 retstr
= HeapAlloc(GetProcessHeap(), 0, size_retstr
);
1192 if (!retstr
) return 0;
1193 memcpy (retstr
, str
, size_retstr
);
1204 len
= sizeof(line
)/sizeof(line
[0]);
1206 last_line
= !(flags
& DT_NOCLIP
) && y
- ((flags
& DT_EDITCONTROL
) ? 2*lh
-1 : lh
) < rect
->bottom
;
1208 last_line
= !(flags
& DT_NOCLIP
) && y
+ ((flags
& DT_EDITCONTROL
) ? 2*lh
-1 : lh
) > rect
->bottom
;
1209 strPtr
= TEXT_NextLineW(hdc
, strPtr
, &count
, line
, &len
, width
, flags
, &size
, last_line
, &p_retstr
, tabwidth
, &prefix_offset
, &ellip
);
1211 if (flags
& DT_CENTER
) x
= (rect
->left
+ rect
->right
-
1213 else if (flags
& DT_RIGHT
) x
= rect
->right
- size
.cx
;
1215 if (flags
& DT_SINGLELINE
)
1217 if (flags
& DT_VCENTER
) y
= rect
->top
+
1218 (rect
->bottom
- rect
->top
) / 2 - size
.cy
/ 2;
1219 else if (flags
& DT_BOTTOM
) y
= rect
->bottom
- size
.cy
;
1222 if (!(flags
& DT_CALCRECT
))
1224 const WCHAR
*str
= line
;
1230 if ((flags
& DT_EXPANDTABS
))
1233 p
= str
; while (p
< str
+len
&& *p
!= TAB
) p
++;
1235 if (len_seg
!= len
&& !GetTextExtentPointW(hdc
, str
, len_seg
, &size
))
1241 if (!ExtTextOutW( hdc
, xseg
, y
,
1242 ((flags
& DT_NOCLIP
) ? 0 : ETO_CLIPPED
) |
1243 ((flags
& DT_RTLREADING
) ? ETO_RTLREADING
: 0),
1244 rect
, str
, len_seg
, NULL
)) return 0;
1245 if (prefix_offset
!= -1 && prefix_offset
< len_seg
)
1247 TEXT_DrawUnderscore (hdc
, xseg
, y
+ tm
.tmAscent
+ 1, str
, prefix_offset
, (flags
& DT_NOCLIP
) ? NULL
: rect
);
1253 assert ((flags
& DT_EXPANDTABS
) && *str
== TAB
);
1255 xseg
+= ((size
.cx
/tabwidth
)+1)*tabwidth
;
1256 if (prefix_offset
!= -1)
1258 if (prefix_offset
< len_seg
)
1260 /* We have just drawn an underscore; we ought to
1261 * figure out where the next one is. I am going
1262 * to leave it for now until I have a better model
1263 * for the line, which will make reprefixing easier.
1264 * This is where ellip would be used.
1269 prefix_offset
-= len_seg
;
1274 else if (size
.cx
> max_width
)
1275 max_width
= size
.cx
;
1282 dtp
->uiLengthDrawn
+= len
;
1284 while (strPtr
&& !last_line
);
1286 if (flags
& DT_CALCRECT
)
1288 rect
->right
= rect
->left
+ max_width
;
1291 rect
->right
+= lmargin
+ rmargin
;
1295 memcpy (str
, retstr
, size_retstr
);
1296 HeapFree (GetProcessHeap(), 0, retstr
);
1298 return y
- rect
->top
;
1301 /***********************************************************************
1302 * DrawTextExA (USER32.@)
1304 * If DT_MODIFYSTRING is specified then there must be room for up to
1305 * 4 extra characters. We take great care about just how much modified
1310 * Synced with wine 1.1.32
1312 INT WINAPI
DrawTextExA( HDC hdc
, LPSTR str
, INT count
,
1313 LPRECT rect
, UINT flags
, LPDRAWTEXTPARAMS dtp
)
1324 if (!count
) return 0;
1325 if (!str
&& count
> 0) return 0;
1326 if( !str
|| ((count
== -1) && !(count
= strlen(str
))))
1331 if (dtp
&& dtp
->cbSize
!= sizeof(DRAWTEXTPARAMS
))
1334 GetTextMetricsA(hdc
, &tm
);
1335 if (flags
& DT_EXTERNALLEADING
)
1336 lh
= tm
.tmHeight
+ tm
.tmExternalLeading
;
1340 if( flags
& DT_CALCRECT
)
1342 rect
->right
= rect
->left
;
1343 if( flags
& DT_SINGLELINE
)
1344 rect
->bottom
= rect
->top
+ lh
;
1346 rect
->bottom
= rect
->top
;
1350 cp
= GdiGetCodePage( hdc
);
1351 wcount
= MultiByteToWideChar( cp
, 0, str
, count
, NULL
, 0 );
1354 if (flags
& DT_MODIFYSTRING
)
1359 wstr
= HeapAlloc(GetProcessHeap(), 0, wmax
* sizeof(WCHAR
));
1362 MultiByteToWideChar( cp
, 0, str
, count
, wstr
, wcount
);
1363 if (flags
& DT_MODIFYSTRING
)
1364 for (i
=4, p
=wstr
+wcount
; i
--; p
++) *p
=0xFFFE;
1365 /* Initialise the extra characters so that we can see which ones
1366 * change. U+FFFE is guaranteed to be not a unicode character and
1367 * so will not be generated by DrawTextEx itself.
1369 ret
= DrawTextExW( hdc
, wstr
, wcount
, rect
, flags
, dtp
);
1370 if (flags
& DT_MODIFYSTRING
)
1372 /* Unfortunately the returned string may contain multiple \0s
1373 * and so we need to measure it ourselves.
1375 for (i
=4, p
=wstr
+wcount
; i
-- && *p
!= 0xFFFE; p
++) wcount
++;
1376 WideCharToMultiByte( cp
, 0, wstr
, wcount
, str
, amax
, NULL
, NULL
);
1378 HeapFree(GetProcessHeap(), 0, wstr
);
1383 /***********************************************************************
1384 * DrawTextW (USER32.@)
1388 INT WINAPI
DrawTextW( HDC hdc
, LPCWSTR str
, INT count
, LPRECT rect
, UINT flags
)
1392 memset (&dtp
, 0, sizeof(dtp
));
1393 dtp
.cbSize
= sizeof(dtp
);
1394 if (flags
& DT_TABSTOP
)
1396 dtp
.iTabLength
= (flags
>> 8) & 0xff;
1397 flags
&= 0xffff00ff;
1399 return DrawTextExW(hdc
, (LPWSTR
)str
, count
, rect
, flags
, &dtp
);
1402 /***********************************************************************
1403 * DrawTextA (USER32.@)
1407 INT WINAPI
DrawTextA( HDC hdc
, LPCSTR str
, INT count
, LPRECT rect
, UINT flags
)
1411 memset (&dtp
, 0, sizeof(dtp
));
1412 dtp
.cbSize
= sizeof(dtp
);
1413 if (flags
& DT_TABSTOP
)
1415 dtp
.iTabLength
= (flags
>> 8) & 0xff;
1416 flags
&= 0xffff00ff;
1418 return DrawTextExA( hdc
, (LPSTR
)str
, count
, rect
, flags
, &dtp
);