Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1 | /* |
| 2 | * USER text functions |
| 3 | * |
| 4 | * Copyright 1993, 1994 Alexandre Julliard |
Bill Medland | 7423dc0 | 2002-02-21 20:07:26 +0000 | [diff] [blame] | 5 | * Copyright 2002 Bill Medland |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 6 | * |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 7 | * Contains |
Bill Medland | fd59f34 | 2002-01-15 20:29:35 +0000 | [diff] [blame] | 8 | * 1. DrawText functions |
| 9 | * 2. GrayString functions |
| 10 | * 3. TabbedText functions |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 11 | * |
| 12 | * This library is free software; you can redistribute it and/or |
| 13 | * modify it under the terms of the GNU Lesser General Public |
| 14 | * License as published by the Free Software Foundation; either |
| 15 | * version 2.1 of the License, or (at your option) any later version. |
| 16 | * |
| 17 | * This library is distributed in the hope that it will be useful, |
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 20 | * Lesser General Public License for more details. |
| 21 | * |
| 22 | * You should have received a copy of the GNU Lesser General Public |
| 23 | * License along with this library; if not, write to the Free Software |
| 24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 25 | */ |
| 26 | |
Alexandre Julliard | 5769d1d | 2002-04-26 19:05:15 +0000 | [diff] [blame] | 27 | #include "config.h" |
| 28 | #include "wine/port.h" |
| 29 | |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 30 | #include <string.h> |
Bill Medland | afe92e8 | 2002-02-05 18:07:04 +0000 | [diff] [blame] | 31 | #include <assert.h> |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 32 | |
| 33 | #include "windef.h" |
| 34 | #include "wingdi.h" |
| 35 | #include "wine/winuser16.h" |
Gerard Patel | 158e2cb | 2000-12-11 03:39:08 +0000 | [diff] [blame] | 36 | #include "wine/unicode.h" |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 37 | #include "winbase.h" |
| 38 | #include "winerror.h" |
| 39 | #include "winnls.h" |
Alexandre Julliard | a41b2cf | 2001-01-15 20:12:55 +0000 | [diff] [blame] | 40 | #include "user.h" |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 41 | #include "wine/debug.h" |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 42 | |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 43 | WINE_DEFAULT_DEBUG_CHANNEL(text); |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 44 | |
Bill Medland | fd59f34 | 2002-01-15 20:29:35 +0000 | [diff] [blame] | 45 | /********************************************************************* |
| 46 | * |
| 47 | * DrawText functions |
Bill Medland | 001e732 | 2002-01-31 20:44:39 +0000 | [diff] [blame] | 48 | * |
| 49 | * Design issues |
| 50 | * How many buffers to use |
| 51 | * While processing in DrawText there are potentially three different forms |
| 52 | * of the text that need to be held. How are they best held? |
| 53 | * 1. The original text is needed, of course, to see what to display. |
| 54 | * 2. The text that will be returned to the user if the DT_MODIFYSTRING is |
| 55 | * in effect. |
| 56 | * 3. The buffered text that is about to be displayed e.g. the current line. |
| 57 | * Typically this will exclude the ampersands used for prefixing etc. |
| 58 | * |
| 59 | * Complications. |
| 60 | * a. If the buffered text to be displayed includes the ampersands then |
| 61 | * we will need special measurement and draw functions that will ignore |
| 62 | * the ampersands (e.g. by copying to a buffer without the prefix and |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 63 | * then using the normal forms). This may involve less space but may |
Bill Medland | 001e732 | 2002-01-31 20:44:39 +0000 | [diff] [blame] | 64 | * require more processing. e.g. since a line containing tabs may |
| 65 | * contain several underlined characters either we need to carry around |
| 66 | * a list of prefix locations or we may need to locate them several |
| 67 | * times. |
| 68 | * b. If we actually directly modify the "original text" as we go then we |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 69 | * will need some special "caching" to handle the fact that when we |
Bill Medland | 001e732 | 2002-01-31 20:44:39 +0000 | [diff] [blame] | 70 | * ellipsify the text the ellipsis may modify the next line of text, |
| 71 | * which we have not yet processed. (e.g. ellipsification of a W at the |
| 72 | * end of a line will overwrite the W, the \n and the first character of |
| 73 | * the next line, and a \0 will overwrite the second. Try it!!) |
| 74 | * |
| 75 | * Option 1. Three separate storages. (To be implemented) |
| 76 | * If DT_MODIFYSTRING is in effect then allocate an extra buffer to hold |
| 77 | * the edited string in some form, either as the string itself or as some |
| 78 | * sort of "edit list" to be applied just before returning. |
| 79 | * Use a buffer that holds the ellipsified current line sans ampersands |
| 80 | * and accept the need occasionally to recalculate the prefixes (if |
| 81 | * DT_EXPANDTABS and not DT_NOPREFIX and not DT_HIDEPREFIX) |
Bill Medland | fd59f34 | 2002-01-15 20:29:35 +0000 | [diff] [blame] | 82 | */ |
| 83 | |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 84 | #define TAB 9 |
| 85 | #define LF 10 |
| 86 | #define CR 13 |
| 87 | #define SPACE 32 |
| 88 | #define PREFIX 38 |
| 89 | |
Susan Farley | 196daf8 | 2000-09-22 22:09:11 +0000 | [diff] [blame] | 90 | #define FORWARD_SLASH '/' |
| 91 | #define BACK_SLASH '\\' |
| 92 | |
Gerard Patel | 158e2cb | 2000-12-11 03:39:08 +0000 | [diff] [blame] | 93 | static const WCHAR ELLIPSISW[] = {'.','.','.', 0}; |
Gerard Patel | 158e2cb | 2000-12-11 03:39:08 +0000 | [diff] [blame] | 94 | |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 95 | typedef struct tag_ellipsis_data |
| 96 | { |
| 97 | int before; |
| 98 | int len; |
| 99 | int under; |
| 100 | int after; |
| 101 | } ellipsis_data; |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 102 | |
Bill Medland | 001e732 | 2002-01-31 20:44:39 +0000 | [diff] [blame] | 103 | /********************************************************************* |
Bill Medland | afe92e8 | 2002-02-05 18:07:04 +0000 | [diff] [blame] | 104 | * TEXT_Ellipsify (static) |
| 105 | * |
| 106 | * Add an ellipsis to the end of the given string whilst ensuring it fits. |
| 107 | * |
| 108 | * If the ellipsis alone doesn't fit then it will be returned anyway. |
| 109 | * |
| 110 | * See Also TEXT_PathEllipsify |
| 111 | * |
| 112 | * Arguments |
| 113 | * hdc [in] The handle to the DC that defines the font. |
| 114 | * str [in/out] The string that needs to be modified. |
| 115 | * max_str [in] The dimension of str (number of WCHAR). |
| 116 | * len_str [in/out] The number of characters in str |
| 117 | * width [in] The maximum width permitted (in logical coordinates) |
| 118 | * size [out] The dimensions of the text |
| 119 | * modstr [out] The modified form of the string, to be returned to the |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 120 | * calling program. It is assumed that the caller has |
Bill Medland | afe92e8 | 2002-02-05 18:07:04 +0000 | [diff] [blame] | 121 | * made sufficient space available so we don't need to |
| 122 | * know the size of the space. This pointer may be NULL if |
| 123 | * the modified string is not required. |
| 124 | * len_before [out] The number of characters before the ellipsis. |
| 125 | * len_ellip [out] The number of characters in the ellipsis. |
| 126 | * |
| 127 | * See for example Microsoft article Q249678. |
| 128 | * |
| 129 | * For now we will simply use three dots rather than worrying about whether |
| 130 | * the font contains an explicit ellipsis character. |
| 131 | */ |
| 132 | static void TEXT_Ellipsify (HDC hdc, WCHAR *str, unsigned int max_len, |
| 133 | unsigned int *len_str, int width, SIZE *size, |
| 134 | WCHAR *modstr, |
| 135 | int *len_before, int *len_ellip) |
| 136 | { |
| 137 | unsigned int len_ellipsis; |
Paul Rupe | 2e2988d | 2002-06-10 22:47:58 +0000 | [diff] [blame] | 138 | unsigned int lo, mid, hi; |
Bill Medland | afe92e8 | 2002-02-05 18:07:04 +0000 | [diff] [blame] | 139 | |
| 140 | len_ellipsis = strlenW (ELLIPSISW); |
| 141 | if (len_ellipsis > max_len) len_ellipsis = max_len; |
| 142 | if (*len_str > max_len - len_ellipsis) |
| 143 | *len_str = max_len - len_ellipsis; |
| 144 | |
Paul Rupe | 2e2988d | 2002-06-10 22:47:58 +0000 | [diff] [blame] | 145 | /* First do a quick binary search to get an upper bound for *len_str. */ |
| 146 | if (*len_str > 0 && |
| 147 | GetTextExtentExPointW(hdc, str, *len_str, width, NULL, NULL, size) && |
| 148 | size->cx > width) |
| 149 | { |
| 150 | for (lo = 0, hi = *len_str; lo < hi; ) |
| 151 | { |
| 152 | mid = (lo + hi) / 2; |
| 153 | if (!GetTextExtentExPointW(hdc, str, mid, width, NULL, NULL, size)) |
| 154 | break; |
| 155 | if (size->cx > width) |
| 156 | hi = mid; |
| 157 | else |
| 158 | lo = mid + 1; |
| 159 | } |
| 160 | *len_str = hi; |
| 161 | } |
| 162 | /* Now this should take only a couple iterations at most. */ |
Bill Medland | afe92e8 | 2002-02-05 18:07:04 +0000 | [diff] [blame] | 163 | for ( ; ; ) |
| 164 | { |
| 165 | strncpyW (str + *len_str, ELLIPSISW, len_ellipsis); |
| 166 | |
| 167 | if (!GetTextExtentExPointW (hdc, str, *len_str + len_ellipsis, width, |
| 168 | NULL, NULL, size)) break; |
| 169 | |
| 170 | if (!*len_str || size->cx <= width) break; |
| 171 | |
| 172 | (*len_str)--; |
| 173 | } |
| 174 | *len_ellip = len_ellipsis; |
| 175 | *len_before = *len_str; |
| 176 | *len_str += len_ellipsis; |
| 177 | |
| 178 | if (modstr) |
| 179 | { |
| 180 | strncpyW (modstr, str, *len_str); |
| 181 | *(str+*len_str) = '\0'; |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | /********************************************************************* |
Bill Medland | 92d77c9 | 2002-02-14 19:21:59 +0000 | [diff] [blame] | 186 | * TEXT_PathEllipsify (static) |
Bill Medland | afe92e8 | 2002-02-05 18:07:04 +0000 | [diff] [blame] | 187 | * |
| 188 | * Add an ellipsis to the provided string in order to make it fit within |
| 189 | * the width. The ellipsis is added as specified for the DT_PATH_ELLIPSIS |
| 190 | * flag. |
| 191 | * |
| 192 | * See Also TEXT_Ellipsify |
| 193 | * |
| 194 | * Arguments |
| 195 | * hdc [in] The handle to the DC that defines the font. |
| 196 | * str [in/out] The string that needs to be modified |
| 197 | * max_str [in] The dimension of str (number of WCHAR). |
| 198 | * len_str [in/out] The number of characters in str |
| 199 | * width [in] The maximum width permitted (in logical coordinates) |
| 200 | * size [out] The dimensions of the text |
| 201 | * modstr [out] The modified form of the string, to be returned to the |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 202 | * calling program. It is assumed that the caller has |
Bill Medland | afe92e8 | 2002-02-05 18:07:04 +0000 | [diff] [blame] | 203 | * made sufficient space available so we don't need to |
| 204 | * know the size of the space. This pointer may be NULL if |
| 205 | * the modified string is not required. |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 206 | * pellip [out] The ellipsification results |
Bill Medland | afe92e8 | 2002-02-05 18:07:04 +0000 | [diff] [blame] | 207 | * |
| 208 | * For now we will simply use three dots rather than worrying about whether |
| 209 | * the font contains an explicit ellipsis character. |
| 210 | * |
| 211 | * The following applies, I think to Win95. We will need to extend it for |
| 212 | * Win98 which can have both path and end ellipsis at the same time (e.g. |
| 213 | * C:\MyLongFileName.Txt becomes ...\MyLongFileN...) |
| 214 | * |
| 215 | * The resulting string consists of as much as possible of the following: |
| 216 | * 1. The ellipsis itself |
| 217 | * 2. The last \ or / of the string (if any) |
| 218 | * 3. Everything after the last \ or / of the string (if any) or the whole |
| 219 | * string if there is no / or \. I believe that under Win95 this would |
| 220 | * include everything even though some might be clipped off the end whereas |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 221 | * under Win98 that might be ellipsified too. |
| 222 | * Yet to be investigated is whether this would include wordbreaking if the |
Bill Medland | afe92e8 | 2002-02-05 18:07:04 +0000 | [diff] [blame] | 223 | * filename is more than 1 word and splitting if DT_EDITCONTROL was in |
| 224 | * effect. (If DT_EDITCONTROL is in effect then on occasions text will be |
| 225 | * broken within words). |
| 226 | * 4. All the stuff before the / or \, which is placed before the ellipsis. |
| 227 | */ |
| 228 | static void TEXT_PathEllipsify (HDC hdc, WCHAR *str, unsigned int max_len, |
| 229 | unsigned int *len_str, int width, SIZE *size, |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 230 | WCHAR *modstr, ellipsis_data *pellip) |
Bill Medland | afe92e8 | 2002-02-05 18:07:04 +0000 | [diff] [blame] | 231 | { |
| 232 | int len_ellipsis; |
| 233 | int len_trailing; |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 234 | int len_under; |
Bill Medland | afe92e8 | 2002-02-05 18:07:04 +0000 | [diff] [blame] | 235 | WCHAR *lastBkSlash, *lastFwdSlash, *lastSlash; |
| 236 | |
| 237 | len_ellipsis = strlenW (ELLIPSISW); |
| 238 | if (!max_len) return; |
| 239 | if (len_ellipsis >= max_len) len_ellipsis = max_len - 1; |
| 240 | if (*len_str + len_ellipsis >= max_len) |
| 241 | *len_str = max_len - len_ellipsis-1; |
| 242 | /* Hopefully this will never happen, otherwise it would probably lose |
| 243 | * the wrong character |
| 244 | */ |
| 245 | str[*len_str] = '\0'; /* to simplify things */ |
| 246 | |
| 247 | lastBkSlash = strrchrW (str, BACK_SLASH); |
| 248 | lastFwdSlash = strrchrW (str, FORWARD_SLASH); |
| 249 | lastSlash = lastBkSlash > lastFwdSlash ? lastBkSlash : lastFwdSlash; |
| 250 | if (!lastSlash) lastSlash = str; |
| 251 | len_trailing = *len_str - (lastSlash - str); |
| 252 | |
| 253 | /* overlap-safe movement to the right */ |
| 254 | memmove (lastSlash+len_ellipsis, lastSlash, len_trailing * sizeof(WCHAR)); |
| 255 | strncpyW (lastSlash, ELLIPSISW, len_ellipsis); |
| 256 | len_trailing += len_ellipsis; |
| 257 | /* From this point on lastSlash actually points to the ellipsis in front |
| 258 | * of the last slash and len_trailing includes the ellipsis |
| 259 | */ |
| 260 | |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 261 | len_under = 0; |
Bill Medland | afe92e8 | 2002-02-05 18:07:04 +0000 | [diff] [blame] | 262 | for ( ; ; ) |
| 263 | { |
| 264 | if (!GetTextExtentExPointW (hdc, str, *len_str + len_ellipsis, width, |
| 265 | NULL, NULL, size)) break; |
| 266 | |
| 267 | if (lastSlash == str || size->cx <= width) break; |
| 268 | |
| 269 | /* overlap-safe movement to the left */ |
| 270 | memmove (lastSlash-1, lastSlash, len_trailing * sizeof(WCHAR)); |
| 271 | lastSlash--; |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 272 | len_under++; |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 273 | |
Bill Medland | afe92e8 | 2002-02-05 18:07:04 +0000 | [diff] [blame] | 274 | assert (*len_str); |
| 275 | (*len_str)--; |
| 276 | } |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 277 | pellip->before = lastSlash-str; |
| 278 | pellip->len = len_ellipsis; |
| 279 | pellip->under = len_under; |
| 280 | pellip->after = len_trailing - len_ellipsis; |
Bill Medland | afe92e8 | 2002-02-05 18:07:04 +0000 | [diff] [blame] | 281 | *len_str += len_ellipsis; |
| 282 | |
| 283 | if (modstr) |
| 284 | { |
| 285 | strncpyW (modstr, str, *len_str); |
| 286 | *(str+*len_str) = '\0'; |
| 287 | } |
| 288 | } |
| 289 | |
Bill Medland | afe92e8 | 2002-02-05 18:07:04 +0000 | [diff] [blame] | 290 | /********************************************************************* |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 291 | * TEXT_WordBreak (static) |
| 292 | * |
| 293 | * Perform wordbreak processing on the given string |
| 294 | * |
| 295 | * Assumes that DT_WORDBREAK has been specified and not all the characters |
Bill Medland | bc39eee | 2002-02-26 00:39:30 +0000 | [diff] [blame] | 296 | * fit. Note that this function should even be called when the first character |
| 297 | * that doesn't fit is known to be a space or tab, so that it can swallow them. |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 298 | * |
Bill Medland | bc39eee | 2002-02-26 00:39:30 +0000 | [diff] [blame] | 299 | * Note that the Windows processing has some strange properties. |
| 300 | * 1. If the text is left-justified and there is room for some of the spaces |
| 301 | * that follow the last word on the line then those that fit are included on |
| 302 | * the line. |
| 303 | * 2. If the text is centred or right-justified and there is room for some of |
| 304 | * the spaces that follow the last word on the line then all but one of those |
| 305 | * that fit are included on the line. |
| 306 | * 3. (Reasonable behaviour) If the word breaking causes a space to be the first |
| 307 | * character of a new line it will be skipped. |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 308 | * |
| 309 | * Arguments |
| 310 | * hdc [in] The handle to the DC that defines the font. |
| 311 | * str [in/out] The string that needs to be broken. |
| 312 | * max_str [in] The dimension of str (number of WCHAR). |
| 313 | * len_str [in/out] The number of characters in str |
| 314 | * width [in] The maximum width permitted |
| 315 | * format [in] The format flags in effect |
| 316 | * chars_fit [in] The maximum number of characters of str that are already |
| 317 | * known to fit; chars_fit+1 is known not to fit. |
| 318 | * chars_used [out] The number of characters of str that have been "used" and |
| 319 | * do not need to be included in later text. For example this will |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 320 | * include any spaces that have been discarded from the start of |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 321 | * the next line. |
| 322 | * size [out] The size of the returned text in logical coordinates |
| 323 | * |
| 324 | * Pedantic assumption - Assumes that the text length is monotonically |
| 325 | * increasing with number of characters (i.e. no weird kernings) |
| 326 | * |
| 327 | * Algorithm |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 328 | * |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 329 | * Work back from the last character that did fit to either a space or the last |
| 330 | * character of a word, whichever is met first. |
| 331 | * If there was one or the first character didn't fit then |
Bill Medland | bc39eee | 2002-02-26 00:39:30 +0000 | [diff] [blame] | 332 | * If the text is centred or right justified and that one character was a |
| 333 | * space then break the line before that character |
| 334 | * Otherwise break the line after that character |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 335 | * and if the next character is a space then discard it. |
| 336 | * Suppose there was none (and the first character did fit). |
| 337 | * If Break Within Word is permitted |
| 338 | * break the word after the last character that fits (there must be |
| 339 | * at least one; none is caught earlier). |
| 340 | * Otherwise |
| 341 | * discard any trailing space. |
| 342 | * include the whole word; it may be ellipsified later |
| 343 | * |
| 344 | * Break Within Word is permitted under a set of circumstances that are not |
| 345 | * totally clear yet. Currently our best guess is: |
| 346 | * If DT_EDITCONTROL is in effect and neither DT_WORD_ELLIPSIS nor |
| 347 | * DT_PATH_ELLIPSIS is |
| 348 | */ |
| 349 | |
| 350 | static void TEXT_WordBreak (HDC hdc, WCHAR *str, unsigned int max_str, |
| 351 | unsigned int *len_str, |
| 352 | int width, int format, unsigned int chars_fit, |
| 353 | unsigned int *chars_used, SIZE *size) |
| 354 | { |
| 355 | WCHAR *p; |
| 356 | int word_fits; |
| 357 | assert (format & DT_WORDBREAK); |
| 358 | assert (chars_fit < *len_str); |
| 359 | |
| 360 | /* Work back from the last character that did fit to either a space or the |
| 361 | * last character of a word, whichever is met first. |
| 362 | */ |
| 363 | p = str + chars_fit; /* The character that doesn't fit */ |
| 364 | word_fits = TRUE; |
| 365 | if (!chars_fit) |
| 366 | ; /* we pretend that it fits anyway */ |
| 367 | else if (*p == SPACE) /* chars_fit < *len_str so this is valid */ |
| 368 | p--; /* the word just fitted */ |
| 369 | else |
| 370 | { |
| 371 | while (p > str && *(--p) != SPACE) |
| 372 | ; |
| 373 | word_fits = (p != str || *p == SPACE); |
| 374 | } |
| 375 | /* If there was one or the first character didn't fit then */ |
| 376 | if (word_fits) |
| 377 | { |
Robert O'Callahan | 71a8a74 | 2002-04-27 00:14:16 +0000 | [diff] [blame] | 378 | int next_is_space; |
Bill Medland | bc39eee | 2002-02-26 00:39:30 +0000 | [diff] [blame] | 379 | /* break the line before/after that character */ |
| 380 | if (!(format & (DT_RIGHT | DT_CENTER)) || *p != SPACE) |
| 381 | p++; |
Robert O'Callahan | 71a8a74 | 2002-04-27 00:14:16 +0000 | [diff] [blame] | 382 | next_is_space = (p - str) < *len_str && *p == SPACE; |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 383 | *len_str = p - str; |
| 384 | /* and if the next character is a space then discard it. */ |
| 385 | *chars_used = *len_str; |
Robert O'Callahan | 71a8a74 | 2002-04-27 00:14:16 +0000 | [diff] [blame] | 386 | if (next_is_space) |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 387 | (*chars_used)++; |
| 388 | } |
| 389 | /* Suppose there was none. */ |
| 390 | else |
| 391 | { |
| 392 | if ((format & (DT_EDITCONTROL | DT_WORD_ELLIPSIS | DT_PATH_ELLIPSIS)) == |
| 393 | DT_EDITCONTROL) |
| 394 | { |
| 395 | /* break the word after the last character that fits (there must be |
| 396 | * at least one; none is caught earlier). |
| 397 | */ |
| 398 | *len_str = chars_fit; |
| 399 | *chars_used = chars_fit; |
| 400 | |
| 401 | /* FIXME - possible error. Since the next character is now removed |
| 402 | * this could make the text longer so that it no longer fits, and |
| 403 | * so we need a loop to test and shrink. |
| 404 | */ |
| 405 | } |
| 406 | /* Otherwise */ |
| 407 | else |
| 408 | { |
| 409 | /* discard any trailing space. */ |
| 410 | const WCHAR *e = str + *len_str; |
| 411 | p = str + chars_fit; |
| 412 | while (p < e && *p != SPACE) |
| 413 | p++; |
| 414 | *chars_used = p - str; |
| 415 | if (p < e) /* i.e. loop failed because *p == SPACE */ |
| 416 | (*chars_used)++; |
| 417 | |
| 418 | /* include the whole word; it may be ellipsified later */ |
| 419 | *len_str = p - str; |
| 420 | /* Possible optimisation; if DT_WORD_ELLIPSIS only use chars_fit+1 |
| 421 | * so that it will be too long |
| 422 | */ |
| 423 | } |
| 424 | } |
| 425 | /* Remeasure the string */ |
| 426 | GetTextExtentExPointW (hdc, str, *len_str, 0, NULL, NULL, size); |
| 427 | } |
| 428 | |
| 429 | /********************************************************************* |
| 430 | * TEXT_SkipChars |
| 431 | * |
| 432 | * Skip over the given number of characters, bearing in mind prefix |
| 433 | * substitution and the fact that a character may take more than one |
| 434 | * WCHAR (Unicode surrogates are two words long) (and there may have been |
| 435 | * a trailing &) |
| 436 | * |
| 437 | * Parameters |
| 438 | * new_count [out] The updated count |
| 439 | * new_str [out] The updated pointer |
| 440 | * start_count [in] The count of remaining characters corresponding to the |
| 441 | * start of the string |
| 442 | * start_str [in] The starting point of the string |
| 443 | * max [in] The number of characters actually in this segment of the |
| 444 | * string (the & counts) |
| 445 | * n [in] The number of characters to skip (if prefix then |
| 446 | * &c counts as one) |
| 447 | * prefix [in] Apply prefix substitution |
| 448 | * |
| 449 | * Return Values |
| 450 | * none |
| 451 | * |
| 452 | * Remarks |
| 453 | * There must be at least n characters in the string |
| 454 | * We need max because the "line" may have ended with a & followed by a tab |
| 455 | * or newline etc. which we don't want to swallow |
| 456 | */ |
| 457 | |
| 458 | static void TEXT_SkipChars (int *new_count, const WCHAR **new_str, |
| 459 | int start_count, const WCHAR *start_str, |
| 460 | int max, int n, int prefix) |
| 461 | { |
| 462 | /* This is specific to wide characters, MSDN doesn't say anything much |
| 463 | * about Unicode surrogates yet and it isn't clear if _wcsinc will |
| 464 | * correctly handle them so we'll just do this the easy way for now |
| 465 | */ |
| 466 | |
| 467 | if (prefix) |
| 468 | { |
| 469 | const WCHAR *str_on_entry = start_str; |
| 470 | assert (max >= n); |
| 471 | max -= n; |
| 472 | while (n--) |
| 473 | if (*start_str++ == PREFIX && max--) |
| 474 | start_str++; |
| 475 | else; |
| 476 | start_count -= (start_str - str_on_entry); |
| 477 | } |
| 478 | else |
| 479 | { |
| 480 | start_str += n; |
| 481 | start_count -= n; |
| 482 | } |
| 483 | *new_str = start_str; |
| 484 | *new_count = start_count; |
| 485 | } |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 486 | |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 487 | /********************************************************************* |
Bill Medland | 001e732 | 2002-01-31 20:44:39 +0000 | [diff] [blame] | 488 | * TEXT_Reprefix |
| 489 | * |
| 490 | * Reanalyse the text to find the prefixed character. This is called when |
| 491 | * wordbreaking or ellipsification has shortened the string such that the |
| 492 | * previously noted prefixed character is no longer visible. |
| 493 | * |
| 494 | * Parameters |
| 495 | * str [in] The original string segment (including all characters) |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 496 | * ns [in] The number of characters in str (including prefixes) |
| 497 | * pe [in] The ellipsification data |
Bill Medland | 001e732 | 2002-01-31 20:44:39 +0000 | [diff] [blame] | 498 | * |
| 499 | * Return Values |
| 500 | * The prefix offset within the new string segment (the one that contains the |
| 501 | * ellipses and does not contain the prefix characters) (-1 if none) |
Bill Medland | 001e732 | 2002-01-31 20:44:39 +0000 | [diff] [blame] | 502 | */ |
| 503 | |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 504 | static int TEXT_Reprefix (const WCHAR *str, unsigned int ns, |
| 505 | const ellipsis_data *pe) |
Bill Medland | 001e732 | 2002-01-31 20:44:39 +0000 | [diff] [blame] | 506 | { |
| 507 | int result = -1; |
| 508 | unsigned int i = 0; |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 509 | unsigned int n = pe->before + pe->under + pe->after; |
| 510 | assert (n <= ns); |
Bill Medland | 001e732 | 2002-01-31 20:44:39 +0000 | [diff] [blame] | 511 | while (i < n) |
| 512 | { |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 513 | if (i == pe->before) |
Bill Medland | 001e732 | 2002-01-31 20:44:39 +0000 | [diff] [blame] | 514 | { |
| 515 | /* Reached the path ellipsis; jump over it */ |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 516 | if (ns < pe->under) break; |
| 517 | str += pe->under; |
| 518 | ns -= pe->under; |
| 519 | i += pe->under; |
| 520 | if (!pe->after) break; /* Nothing after the path ellipsis */ |
Bill Medland | 001e732 | 2002-01-31 20:44:39 +0000 | [diff] [blame] | 521 | } |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 522 | if (!ns) break; |
| 523 | ns--; |
Bill Medland | 001e732 | 2002-01-31 20:44:39 +0000 | [diff] [blame] | 524 | if (*str++ == PREFIX) |
| 525 | { |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 526 | if (!ns) break; |
| 527 | if (*str != PREFIX) |
| 528 | result = (i < pe->before || pe->under == 0) ? i : i - pe->under + pe->len; |
| 529 | /* pe->len may be non-zero while pe_under is zero */ |
Bill Medland | 001e732 | 2002-01-31 20:44:39 +0000 | [diff] [blame] | 530 | str++; |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 531 | ns--; |
Bill Medland | 001e732 | 2002-01-31 20:44:39 +0000 | [diff] [blame] | 532 | } |
| 533 | else; |
| 534 | i++; |
| 535 | } |
| 536 | return result; |
| 537 | } |
Alexandre Julliard | 7e49205 | 2001-12-17 21:37:53 +0000 | [diff] [blame] | 538 | |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 539 | /********************************************************************* |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 540 | * Returns true if and only if the remainder of the line is a single |
Bill Medland | 7423dc0 | 2002-02-21 20:07:26 +0000 | [diff] [blame] | 541 | * newline representation or nothing |
| 542 | */ |
| 543 | |
| 544 | static int remainder_is_none_or_newline (int num_chars, const WCHAR *str) |
| 545 | { |
| 546 | if (!num_chars) return TRUE; |
| 547 | if (*str != LF && *str != CR) return FALSE; |
| 548 | if (!--num_chars) return TRUE; |
| 549 | if (*str == *(str+1)) return FALSE; |
| 550 | str++; |
| 551 | if (*str != CR && *str != LF) return FALSE; |
| 552 | if (--num_chars) return FALSE; |
| 553 | return TRUE; |
| 554 | } |
| 555 | |
| 556 | /********************************************************************* |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 557 | * Return next line of text from a string. |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 558 | * |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 559 | * hdc - handle to DC. |
| 560 | * str - string to parse into lines. |
| 561 | * count - length of str. |
| 562 | * dest - destination in which to return line. |
Ulrich Czekalla | ebc5fe9 | 2001-01-20 02:16:52 +0000 | [diff] [blame] | 563 | * len - dest buffer size in chars on input, copied length into dest on output. |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 564 | * width - maximum width of line in pixels. |
| 565 | * format - format type passed to DrawText. |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 566 | * retsize - returned size of the line in pixels. |
Bill Medland | 7423dc0 | 2002-02-21 20:07:26 +0000 | [diff] [blame] | 567 | * last_line - TRUE if is the last line that will be processed |
| 568 | * p_retstr - If DT_MODIFYSTRING this points to a cursor in the buffer in which |
| 569 | * the return string is built. |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 570 | * tabwidth - The width of a tab in logical coordinates |
| 571 | * pprefix_offset - Here is where we return the offset within dest of the first |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 572 | * prefixed (underlined) character. -1 is returned if there |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 573 | * are none. Note that there may be more; the calling code |
| 574 | * will need to use TEXT_Reprefix to find any later ones. |
| 575 | * pellip - Here is where we return the information about any ellipsification |
| 576 | * that was carried out. Note that if tabs are being expanded then |
| 577 | * this data will correspond to the last text segment actually |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 578 | * returned in dest; by definition there would not have been any |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 579 | * ellipsification in earlier text segments of the line. |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 580 | * |
| 581 | * Returns pointer to next char in str after end of the line |
| 582 | * or NULL if end of str reached. |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 583 | */ |
Gerard Patel | 158e2cb | 2000-12-11 03:39:08 +0000 | [diff] [blame] | 584 | static const WCHAR *TEXT_NextLineW( HDC hdc, const WCHAR *str, int *count, |
Bill Medland | 7423dc0 | 2002-02-21 20:07:26 +0000 | [diff] [blame] | 585 | WCHAR *dest, int *len, int width, DWORD format, |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 586 | SIZE *retsize, int last_line, WCHAR **p_retstr, |
| 587 | int tabwidth, int *pprefix_offset, |
| 588 | ellipsis_data *pellip) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 589 | { |
Bill Medland | cabe8ca | 2002-02-12 18:40:36 +0000 | [diff] [blame] | 590 | int i = 0, j = 0; |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 591 | int plen = 0; |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 592 | SIZE size; |
Ulrich Czekalla | ebc5fe9 | 2001-01-20 02:16:52 +0000 | [diff] [blame] | 593 | int maxl = *len; |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 594 | int seg_i, seg_count, seg_j; |
| 595 | int max_seg_width; |
| 596 | int num_fit; |
| 597 | int word_broken; |
Bill Medland | 8513907 | 2002-02-20 18:56:18 +0000 | [diff] [blame] | 598 | int line_fits; |
| 599 | int j_in_seg; |
Bill Medland | 7423dc0 | 2002-02-21 20:07:26 +0000 | [diff] [blame] | 600 | int ellipsified; |
Bill Medland | 2162eb8 | 2002-03-22 00:12:15 +0000 | [diff] [blame] | 601 | *pprefix_offset = -1; |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 602 | |
| 603 | /* For each text segment in the line */ |
| 604 | |
| 605 | retsize->cy = 0; |
| 606 | while (*count) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 607 | { |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 608 | |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 609 | /* Skip any leading tabs */ |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 610 | |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 611 | if (str[i] == TAB && (format & DT_EXPANDTABS)) |
Bill Medland | cabe8ca | 2002-02-12 18:40:36 +0000 | [diff] [blame] | 612 | { |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 613 | plen = ((plen/tabwidth)+1)*tabwidth; |
| 614 | (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++; |
| 615 | while (*count && str[i] == TAB) |
| 616 | { |
| 617 | plen += tabwidth; |
| 618 | (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++; |
| 619 | } |
Bill Medland | cabe8ca | 2002-02-12 18:40:36 +0000 | [diff] [blame] | 620 | } |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 621 | |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 622 | |
| 623 | /* Now copy as far as the next tab or cr/lf or eos */ |
| 624 | |
| 625 | seg_i = i; |
| 626 | seg_count = *count; |
| 627 | seg_j = j; |
| 628 | |
| 629 | while (*count && |
| 630 | (str[i] != TAB || !(format & DT_EXPANDTABS)) && |
| 631 | ((str[i] != CR && str[i] != LF) || (format & DT_SINGLELINE))) |
| 632 | { |
| 633 | if (str[i] == PREFIX && !(format & DT_NOPREFIX) && *count > 1) |
| 634 | { |
| 635 | (*count)--, i++; /* Throw away the prefix itself */ |
| 636 | if (str[i] == PREFIX) |
| 637 | { |
| 638 | /* Swallow it before we see it again */ |
| 639 | (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++; |
| 640 | } |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 641 | else if (*pprefix_offset == -1 || *pprefix_offset >= seg_j) |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 642 | { |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 643 | *pprefix_offset = j; |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 644 | } |
Bill Medland | 8513907 | 2002-02-20 18:56:18 +0000 | [diff] [blame] | 645 | /* else the previous prefix was in an earlier segment of the |
| 646 | * line; we will leave it to the drawing code to catch this |
| 647 | * one. |
| 648 | */ |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 649 | } |
| 650 | else |
| 651 | { |
| 652 | (*count)--; if (j < maxl) dest[j++] = str[i++]; else i++; |
| 653 | } |
| 654 | } |
| 655 | |
| 656 | |
Bill Medland | 7423dc0 | 2002-02-21 20:07:26 +0000 | [diff] [blame] | 657 | /* Measure the whole text segment and possibly WordBreak and |
| 658 | * ellipsify it |
| 659 | */ |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 660 | |
Bill Medland | 8513907 | 2002-02-20 18:56:18 +0000 | [diff] [blame] | 661 | j_in_seg = j - seg_j; |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 662 | max_seg_width = width - plen; |
Bill Medland | 8513907 | 2002-02-20 18:56:18 +0000 | [diff] [blame] | 663 | GetTextExtentExPointW (hdc, dest + seg_j, j_in_seg, max_seg_width, &num_fit, NULL, &size); |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 664 | |
Bill Medland | 7423dc0 | 2002-02-21 20:07:26 +0000 | [diff] [blame] | 665 | /* The Microsoft handling of various combinations of formats is weird. |
| 666 | * The following may very easily be incorrect if several formats are |
| 667 | * combined, and may differ between versions (to say nothing of the |
| 668 | * several bugs in the Microsoft versions). |
| 669 | */ |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 670 | word_broken = 0; |
Bill Medland | 8513907 | 2002-02-20 18:56:18 +0000 | [diff] [blame] | 671 | line_fits = (num_fit >= j_in_seg); |
| 672 | if (!line_fits && (format & DT_WORDBREAK)) |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 673 | { |
| 674 | const WCHAR *s; |
| 675 | int chars_used; |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 676 | TEXT_WordBreak (hdc, dest+seg_j, maxl-seg_j, &j_in_seg, |
| 677 | max_seg_width, format, num_fit, &chars_used, &size); |
Bill Medland | 8513907 | 2002-02-20 18:56:18 +0000 | [diff] [blame] | 678 | line_fits = (size.cx <= max_seg_width); |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 679 | /* and correct the counts */ |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 680 | TEXT_SkipChars (count, &s, seg_count, str+seg_i, i-seg_i, |
| 681 | chars_used, !(format & DT_NOPREFIX)); |
| 682 | i = s - str; |
| 683 | word_broken = 1; |
| 684 | } |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 685 | pellip->before = j_in_seg; |
| 686 | pellip->under = 0; |
| 687 | pellip->after = 0; |
| 688 | pellip->len = 0; |
Bill Medland | 7423dc0 | 2002-02-21 20:07:26 +0000 | [diff] [blame] | 689 | ellipsified = 0; |
| 690 | if (!line_fits && (format & DT_PATH_ELLIPSIS)) |
| 691 | { |
| 692 | TEXT_PathEllipsify (hdc, dest + seg_j, maxl-seg_j, &j_in_seg, |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 693 | max_seg_width, &size, *p_retstr, pellip); |
Bill Medland | 7423dc0 | 2002-02-21 20:07:26 +0000 | [diff] [blame] | 694 | line_fits = (size.cx <= max_seg_width); |
| 695 | ellipsified = 1; |
| 696 | } |
| 697 | /* NB we may end up ellipsifying a word-broken or path_ellipsified |
| 698 | * string */ |
| 699 | if ((!line_fits && (format & DT_WORD_ELLIPSIS)) || |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 700 | ((format & DT_END_ELLIPSIS) && |
Bill Medland | 7423dc0 | 2002-02-21 20:07:26 +0000 | [diff] [blame] | 701 | ((last_line && *count) || |
| 702 | (remainder_is_none_or_newline (*count, &str[i]) && !line_fits)))) |
| 703 | { |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 704 | int before, len_ellipsis; |
Bill Medland | 7423dc0 | 2002-02-21 20:07:26 +0000 | [diff] [blame] | 705 | TEXT_Ellipsify (hdc, dest + seg_j, maxl-seg_j, &j_in_seg, |
| 706 | max_seg_width, &size, *p_retstr, &before, &len_ellipsis); |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 707 | if (before > pellip->before) |
Bill Medland | 7423dc0 | 2002-02-21 20:07:26 +0000 | [diff] [blame] | 708 | { |
| 709 | /* We must have done a path ellipsis too */ |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 710 | pellip->after = before - pellip->before - pellip->len; |
| 711 | /* Leave the len as the length of the first ellipsis */ |
Bill Medland | 7423dc0 | 2002-02-21 20:07:26 +0000 | [diff] [blame] | 712 | } |
| 713 | else |
| 714 | { |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 715 | /* If we are here after a path ellipsification it must be |
| 716 | * because even the ellipsis itself didn't fit. |
| 717 | */ |
| 718 | assert (pellip->under == 0 && pellip->after == 0); |
| 719 | pellip->before = before; |
| 720 | pellip->len = len_ellipsis; |
| 721 | /* pellip->after remains as zero as does |
| 722 | * pellip->under |
Bill Medland | 7423dc0 | 2002-02-21 20:07:26 +0000 | [diff] [blame] | 723 | */ |
| 724 | } |
| 725 | line_fits = (size.cx <= max_seg_width); |
| 726 | ellipsified = 1; |
| 727 | } |
| 728 | /* As an optimisation if we have ellipsified and we are expanding |
| 729 | * tabs and we haven't reached the end of the line we can skip to it |
| 730 | * now rather than going around the loop again. |
| 731 | */ |
| 732 | if ((format & DT_EXPANDTABS) && ellipsified) |
| 733 | { |
| 734 | if (format & DT_SINGLELINE) |
| 735 | *count = 0; |
| 736 | else |
| 737 | { |
| 738 | while ((*count) && str[i] != CR && str[i] != LF) |
| 739 | { |
| 740 | (*count)--, i++; |
| 741 | } |
| 742 | } |
| 743 | } |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 744 | |
Bill Medland | 8513907 | 2002-02-20 18:56:18 +0000 | [diff] [blame] | 745 | j = seg_j + j_in_seg; |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 746 | if (*pprefix_offset >= seg_j + pellip->before) |
Bill Medland | 7423dc0 | 2002-02-21 20:07:26 +0000 | [diff] [blame] | 747 | { |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 748 | *pprefix_offset = TEXT_Reprefix (str + seg_i, i - seg_i, pellip); |
| 749 | if (*pprefix_offset != -1) |
| 750 | *pprefix_offset += seg_j; |
Bill Medland | 7423dc0 | 2002-02-21 20:07:26 +0000 | [diff] [blame] | 751 | } |
Bill Medland | 8513907 | 2002-02-20 18:56:18 +0000 | [diff] [blame] | 752 | |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 753 | plen += size.cx; |
| 754 | if (size.cy > retsize->cy) |
| 755 | retsize->cy = size.cy; |
| 756 | |
| 757 | if (word_broken) |
| 758 | break; |
| 759 | else if (!*count) |
| 760 | break; |
| 761 | else if (str[i] == CR || str[i] == LF) |
| 762 | { |
Bill Medland | 8513907 | 2002-02-20 18:56:18 +0000 | [diff] [blame] | 763 | (*count)--, i++; |
| 764 | if (*count && (str[i] == CR || str[i] == LF) && str[i] != str[i-1]) |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 765 | { |
Bill Medland | 8513907 | 2002-02-20 18:56:18 +0000 | [diff] [blame] | 766 | (*count)--, i++; |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 767 | } |
| 768 | break; |
| 769 | } |
| 770 | /* else it was a Tab and we go around again */ |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 771 | } |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 772 | |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 773 | retsize->cx = plen; |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 774 | *len = j; |
Bill Medland | 7af9098 | 2002-02-19 18:25:53 +0000 | [diff] [blame] | 775 | if (*count) |
| 776 | return (&str[i]); |
| 777 | else |
| 778 | return NULL; |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 779 | } |
| 780 | |
| 781 | |
| 782 | /*********************************************************************** |
Bill Medland | a4605ac | 2002-01-29 02:46:09 +0000 | [diff] [blame] | 783 | * TEXT_DrawUnderscore |
| 784 | * |
| 785 | * Draw the underline under the prefixed character |
| 786 | * |
| 787 | * Parameters |
| 788 | * hdc [in] The handle of the DC for drawing |
| 789 | * x [in] The x location of the line segment (logical coordinates) |
| 790 | * y [in] The y location of where the underscore should appear |
| 791 | * (logical coordinates) |
| 792 | * str [in] The text of the line segment |
| 793 | * offset [in] The offset of the underscored character within str |
| 794 | */ |
| 795 | |
| 796 | static void TEXT_DrawUnderscore (HDC hdc, int x, int y, const WCHAR *str, int offset) |
| 797 | { |
| 798 | int prefix_x; |
| 799 | int prefix_end; |
| 800 | SIZE size; |
| 801 | HPEN hpen; |
| 802 | HPEN oldPen; |
| 803 | |
| 804 | GetTextExtentPointW (hdc, str, offset, &size); |
| 805 | prefix_x = x + size.cx; |
| 806 | GetTextExtentPointW (hdc, str, offset+1, &size); |
| 807 | prefix_end = x + size.cx - 1; |
| 808 | /* The above method may eventually be slightly wrong due to kerning etc. */ |
| 809 | |
| 810 | hpen = CreatePen (PS_SOLID, 1, GetTextColor (hdc)); |
| 811 | oldPen = SelectObject (hdc, hpen); |
| 812 | MoveToEx (hdc, prefix_x, y, NULL); |
| 813 | LineTo (hdc, prefix_end, y); |
| 814 | SelectObject (hdc, oldPen); |
| 815 | DeleteObject (hpen); |
| 816 | } |
| 817 | |
| 818 | /*********************************************************************** |
Patrik Stridvall | 0c61028 | 2001-01-25 22:22:21 +0000 | [diff] [blame] | 819 | * DrawTextExW (USER32.@) |
Bill Medland | fdb799a | 2002-02-02 18:14:35 +0000 | [diff] [blame] | 820 | * |
| 821 | * The documentation on the extra space required for DT_MODIFYSTRING at MSDN |
| 822 | * is not quite complete, especially with regard to \0. We will assume that |
| 823 | * the returned string could have a length of up to i_count+3 and also have |
| 824 | * a trailing \0 (which would be 4 more than a not-null-terminated string but |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 825 | * 3 more than a null-terminated string). If this is not so then increase |
Bill Medland | fdb799a | 2002-02-02 18:14:35 +0000 | [diff] [blame] | 826 | * the allowance in DrawTextExA. |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 827 | */ |
Ulrich Czekalla | ebc5fe9 | 2001-01-20 02:16:52 +0000 | [diff] [blame] | 828 | #define MAX_STATIC_BUFFER 1024 |
Travis Michielsen | 188b32b | 2001-07-26 20:10:40 +0000 | [diff] [blame] | 829 | INT WINAPI DrawTextExW( HDC hdc, LPWSTR str, INT i_count, |
| 830 | LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp ) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 831 | { |
| 832 | SIZE size; |
Gerard Patel | 158e2cb | 2000-12-11 03:39:08 +0000 | [diff] [blame] | 833 | const WCHAR *strPtr; |
Bill Medland | 8513907 | 2002-02-20 18:56:18 +0000 | [diff] [blame] | 834 | WCHAR *retstr, *p_retstr; |
| 835 | size_t size_retstr; |
Ulrich Czekalla | ebc5fe9 | 2001-01-20 02:16:52 +0000 | [diff] [blame] | 836 | static WCHAR line[MAX_STATIC_BUFFER]; |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 837 | int len, lh, count=i_count; |
Gerard Patel | 158e2cb | 2000-12-11 03:39:08 +0000 | [diff] [blame] | 838 | TEXTMETRICW tm; |
Travis Michielsen | 188b32b | 2001-07-26 20:10:40 +0000 | [diff] [blame] | 839 | int lmargin = 0, rmargin = 0; |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 840 | int x = rect->left, y = rect->top; |
| 841 | int width = rect->right - rect->left; |
| 842 | int max_width = 0; |
Bill Medland | 8513907 | 2002-02-20 18:56:18 +0000 | [diff] [blame] | 843 | int last_line; |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 844 | int tabwidth /* to keep gcc happy */ = 0; |
| 845 | int prefix_offset; |
| 846 | ellipsis_data ellip; |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 847 | |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 848 | TRACE("%s, %d , [(%d,%d),(%d,%d)]\n", debugstr_wn (str, count), count, |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 849 | rect->left, rect->top, rect->right, rect->bottom); |
| 850 | |
Travis Michielsen | 188b32b | 2001-07-26 20:10:40 +0000 | [diff] [blame] | 851 | if (dtp) TRACE("Params: iTabLength=%d, iLeftMargin=%d, iRightMargin=%d\n", |
| 852 | dtp->iTabLength, dtp->iLeftMargin, dtp->iRightMargin); |
Gerard Patel | 158e2cb | 2000-12-11 03:39:08 +0000 | [diff] [blame] | 853 | |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 854 | if (!str) return 0; |
Gerard Patel | 158e2cb | 2000-12-11 03:39:08 +0000 | [diff] [blame] | 855 | if (count == -1) count = strlenW(str); |
Susan Farley | 196daf8 | 2000-09-22 22:09:11 +0000 | [diff] [blame] | 856 | if (count == 0) return 0; |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 857 | strPtr = str; |
| 858 | |
Bill Medland | 0f9013f | 2002-02-15 18:21:59 +0000 | [diff] [blame] | 859 | if (flags & DT_SINGLELINE) |
| 860 | flags &= ~DT_WORDBREAK; |
| 861 | |
Gerard Patel | 158e2cb | 2000-12-11 03:39:08 +0000 | [diff] [blame] | 862 | GetTextMetricsW(hdc, &tm); |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 863 | if (flags & DT_EXTERNALLEADING) |
| 864 | lh = tm.tmHeight + tm.tmExternalLeading; |
| 865 | else |
| 866 | lh = tm.tmHeight; |
| 867 | |
Travis Michielsen | 188b32b | 2001-07-26 20:10:40 +0000 | [diff] [blame] | 868 | if (dtp) |
| 869 | { |
| 870 | lmargin = dtp->iLeftMargin * tm.tmAveCharWidth; |
| 871 | rmargin = dtp->iRightMargin * tm.tmAveCharWidth; |
| 872 | if (!(flags & (DT_CENTER | DT_RIGHT))) |
| 873 | x += lmargin; |
| 874 | dtp->uiLengthDrawn = 0; /* This param RECEIVES number of chars processed */ |
| 875 | } |
| 876 | |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 877 | if (flags & DT_EXPANDTABS) |
| 878 | { |
Bill Medland | cabe8ca | 2002-02-12 18:40:36 +0000 | [diff] [blame] | 879 | int tabstop = ((flags & DT_TABSTOP) && dtp) ? dtp->iTabLength : 8; |
| 880 | tabwidth = tm.tmAveCharWidth * tabstop; |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 881 | } |
| 882 | |
| 883 | if (flags & DT_CALCRECT) flags |= DT_NOCLIP; |
| 884 | |
Bill Medland | 8513907 | 2002-02-20 18:56:18 +0000 | [diff] [blame] | 885 | if (flags & DT_MODIFYSTRING) |
| 886 | { |
| 887 | size_retstr = (count + 4) * sizeof (WCHAR); |
| 888 | retstr = HeapAlloc(GetProcessHeap(), 0, size_retstr); |
| 889 | if (!retstr) return 0; |
| 890 | memcpy (retstr, str, size_retstr); |
| 891 | } |
| 892 | else |
| 893 | { |
| 894 | size_retstr = 0; |
| 895 | retstr = NULL; |
| 896 | } |
| 897 | p_retstr = retstr; |
| 898 | |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 899 | do |
| 900 | { |
Ulrich Czekalla | ebc5fe9 | 2001-01-20 02:16:52 +0000 | [diff] [blame] | 901 | len = MAX_STATIC_BUFFER; |
Bill Medland | 8513907 | 2002-02-20 18:56:18 +0000 | [diff] [blame] | 902 | last_line = !(flags & DT_NOCLIP) && y + ((flags & DT_EDITCONTROL) ? 2*lh-1 : lh) > rect->bottom; |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 903 | strPtr = TEXT_NextLineW(hdc, strPtr, &count, line, &len, width, flags, &size, last_line, &p_retstr, tabwidth, &prefix_offset, &ellip); |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 904 | |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 905 | if (flags & DT_CENTER) x = (rect->left + rect->right - |
| 906 | size.cx) / 2; |
| 907 | else if (flags & DT_RIGHT) x = rect->right - size.cx; |
| 908 | |
| 909 | if (flags & DT_SINGLELINE) |
| 910 | { |
Travis Michielsen | 188b32b | 2001-07-26 20:10:40 +0000 | [diff] [blame] | 911 | if (flags & DT_VCENTER) y = rect->top + |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 912 | (rect->bottom - rect->top) / 2 - size.cy / 2; |
| 913 | else if (flags & DT_BOTTOM) y = rect->bottom - size.cy; |
Bill Medland | fcb8e0d | 2002-01-18 18:09:09 +0000 | [diff] [blame] | 914 | } |
Susan Farley | 196daf8 | 2000-09-22 22:09:11 +0000 | [diff] [blame] | 915 | |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 916 | if (!(flags & DT_CALCRECT)) |
| 917 | { |
Bill Medland | cabe8ca | 2002-02-12 18:40:36 +0000 | [diff] [blame] | 918 | const WCHAR *str = line; |
| 919 | int xseg = x; |
| 920 | while (len) |
| 921 | { |
| 922 | int len_seg; |
| 923 | SIZE size; |
| 924 | if ((flags & DT_EXPANDTABS)) |
| 925 | { |
| 926 | const WCHAR *p; |
| 927 | p = str; while (p < str+len && *p != TAB) p++; |
| 928 | len_seg = p - str; |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 929 | if (len_seg != len && !GetTextExtentPointW(hdc, str, len_seg, &size)) |
Bill Medland | cabe8ca | 2002-02-12 18:40:36 +0000 | [diff] [blame] | 930 | return 0; |
| 931 | } |
| 932 | else |
| 933 | len_seg = len; |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 934 | |
Bill Medland | cabe8ca | 2002-02-12 18:40:36 +0000 | [diff] [blame] | 935 | if (!ExtTextOutW( hdc, xseg, y, |
| 936 | ((flags & DT_NOCLIP) ? 0 : ETO_CLIPPED) | |
| 937 | ((flags & DT_RTLREADING) ? ETO_RTLREADING : 0), |
| 938 | rect, str, len_seg, NULL )) return 0; |
| 939 | if (prefix_offset != -1 && prefix_offset < len_seg) |
| 940 | { |
| 941 | TEXT_DrawUnderscore (hdc, xseg, y + tm.tmAscent + 1, str, prefix_offset); |
| 942 | } |
| 943 | len -= len_seg; |
| 944 | str += len_seg; |
| 945 | if (len) |
| 946 | { |
| 947 | assert ((flags & DT_EXPANDTABS) && *str == TAB); |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 948 | len--; str++; |
Bill Medland | cabe8ca | 2002-02-12 18:40:36 +0000 | [diff] [blame] | 949 | xseg += ((size.cx/tabwidth)+1)*tabwidth; |
| 950 | if (prefix_offset != -1) |
| 951 | { |
| 952 | if (prefix_offset < len_seg) |
| 953 | { |
| 954 | /* We have just drawn an underscore; we ought to |
| 955 | * figure out where the next one is. I am going |
| 956 | * to leave it for now until I have a better model |
Bill Medland | 7d983d2 | 2002-03-11 01:15:31 +0000 | [diff] [blame] | 957 | * for the line, which will make reprefixing easier. |
| 958 | * This is where ellip would be used. |
Bill Medland | cabe8ca | 2002-02-12 18:40:36 +0000 | [diff] [blame] | 959 | */ |
| 960 | prefix_offset = -1; |
| 961 | } |
| 962 | else |
| 963 | prefix_offset -= len_seg; |
| 964 | } |
| 965 | } |
| 966 | } |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 967 | } |
| 968 | else if (size.cx > max_width) |
| 969 | max_width = size.cx; |
| 970 | |
| 971 | y += lh; |
Travis Michielsen | 188b32b | 2001-07-26 20:10:40 +0000 | [diff] [blame] | 972 | if (dtp) |
| 973 | dtp->uiLengthDrawn += len; |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 974 | } |
Bill Medland | 8513907 | 2002-02-20 18:56:18 +0000 | [diff] [blame] | 975 | while (strPtr && !last_line); |
Travis Michielsen | 188b32b | 2001-07-26 20:10:40 +0000 | [diff] [blame] | 976 | |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 977 | if (flags & DT_CALCRECT) |
| 978 | { |
| 979 | rect->right = rect->left + max_width; |
| 980 | rect->bottom = y; |
Travis Michielsen | 188b32b | 2001-07-26 20:10:40 +0000 | [diff] [blame] | 981 | if (dtp) |
| 982 | rect->right += lmargin + rmargin; |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 983 | } |
Bill Medland | 8513907 | 2002-02-20 18:56:18 +0000 | [diff] [blame] | 984 | if (retstr) |
| 985 | { |
| 986 | memcpy (str, retstr, size_retstr); |
| 987 | HeapFree (GetProcessHeap(), 0, retstr); |
| 988 | } |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 989 | return y - rect->top; |
| 990 | } |
| 991 | |
Gerard Patel | 158e2cb | 2000-12-11 03:39:08 +0000 | [diff] [blame] | 992 | /*********************************************************************** |
Travis Michielsen | 188b32b | 2001-07-26 20:10:40 +0000 | [diff] [blame] | 993 | * DrawTextExA (USER32.@) |
Bill Medland | fdb799a | 2002-02-02 18:14:35 +0000 | [diff] [blame] | 994 | * |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 995 | * If DT_MODIFYSTRING is specified then there must be room for up to |
Bill Medland | fdb799a | 2002-02-02 18:14:35 +0000 | [diff] [blame] | 996 | * 4 extra characters. We take great care about just how much modified |
| 997 | * string we return. |
Gerard Patel | 158e2cb | 2000-12-11 03:39:08 +0000 | [diff] [blame] | 998 | */ |
Travis Michielsen | 188b32b | 2001-07-26 20:10:40 +0000 | [diff] [blame] | 999 | INT WINAPI DrawTextExA( HDC hdc, LPSTR str, INT count, |
| 1000 | LPRECT rect, UINT flags, LPDRAWTEXTPARAMS dtp ) |
Gerard Patel | 158e2cb | 2000-12-11 03:39:08 +0000 | [diff] [blame] | 1001 | { |
| 1002 | WCHAR *wstr; |
Bill Medland | fdb799a | 2002-02-02 18:14:35 +0000 | [diff] [blame] | 1003 | WCHAR *p; |
Gerard Patel | 158e2cb | 2000-12-11 03:39:08 +0000 | [diff] [blame] | 1004 | INT ret = 0; |
Bill Medland | fdb799a | 2002-02-02 18:14:35 +0000 | [diff] [blame] | 1005 | int i; |
Gerard Patel | 158e2cb | 2000-12-11 03:39:08 +0000 | [diff] [blame] | 1006 | DWORD wcount; |
Bill Medland | fdb799a | 2002-02-02 18:14:35 +0000 | [diff] [blame] | 1007 | DWORD wmax; |
| 1008 | DWORD amax; |
Gerard Patel | 158e2cb | 2000-12-11 03:39:08 +0000 | [diff] [blame] | 1009 | |
Stefan Leichter | 32b6ef3 | 2002-04-05 21:17:00 +0000 | [diff] [blame] | 1010 | if (!str) return 0; |
Gerard Patel | 158e2cb | 2000-12-11 03:39:08 +0000 | [diff] [blame] | 1011 | if (count == -1) count = strlen(str); |
| 1012 | if (!count) return 0; |
| 1013 | wcount = MultiByteToWideChar( CP_ACP, 0, str, count, NULL, 0 ); |
Bill Medland | fdb799a | 2002-02-02 18:14:35 +0000 | [diff] [blame] | 1014 | wmax = wcount; |
| 1015 | amax = count; |
| 1016 | if (flags & DT_MODIFYSTRING) |
| 1017 | { |
| 1018 | wmax += 4; |
| 1019 | amax += 4; |
| 1020 | } |
| 1021 | wstr = HeapAlloc(GetProcessHeap(), 0, wmax * sizeof(WCHAR)); |
Gerard Patel | 158e2cb | 2000-12-11 03:39:08 +0000 | [diff] [blame] | 1022 | if (wstr) |
| 1023 | { |
| 1024 | MultiByteToWideChar( CP_ACP, 0, str, count, wstr, wcount ); |
Bill Medland | fdb799a | 2002-02-02 18:14:35 +0000 | [diff] [blame] | 1025 | if (flags & DT_MODIFYSTRING) |
| 1026 | for (i=4, p=wstr+wcount; i--; p++) *p=0xFFFE; |
| 1027 | /* Initialise the extra characters so that we can see which ones |
| 1028 | * change. U+FFFE is guaranteed to be not a unicode character and |
| 1029 | * so will not be generated by DrawTextEx itself. |
| 1030 | */ |
Gerard Patel | 158e2cb | 2000-12-11 03:39:08 +0000 | [diff] [blame] | 1031 | ret = DrawTextExW( hdc, wstr, wcount, rect, flags, NULL ); |
Travis Michielsen | 188b32b | 2001-07-26 20:10:40 +0000 | [diff] [blame] | 1032 | if (flags & DT_MODIFYSTRING) |
Bill Medland | fdb799a | 2002-02-02 18:14:35 +0000 | [diff] [blame] | 1033 | { |
| 1034 | /* Unfortunately the returned string may contain multiple \0s |
| 1035 | * and so we need to measure it ourselves. |
| 1036 | */ |
| 1037 | for (i=4, p=wstr+wcount; i-- && *p != 0xFFFE; p++) wcount++; |
| 1038 | WideCharToMultiByte( CP_ACP, 0, wstr, wcount, str, amax, NULL, NULL ); |
| 1039 | } |
Gerard Patel | 158e2cb | 2000-12-11 03:39:08 +0000 | [diff] [blame] | 1040 | HeapFree(GetProcessHeap(), 0, wstr); |
| 1041 | } |
| 1042 | return ret; |
| 1043 | } |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1044 | |
| 1045 | /*********************************************************************** |
Patrik Stridvall | 0c61028 | 2001-01-25 22:22:21 +0000 | [diff] [blame] | 1046 | * DrawTextW (USER32.@) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1047 | */ |
Travis Michielsen | 188b32b | 2001-07-26 20:10:40 +0000 | [diff] [blame] | 1048 | INT WINAPI DrawTextW( HDC hdc, LPCWSTR str, INT count, LPRECT rect, UINT flags ) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1049 | { |
Bill Medland | fd59f34 | 2002-01-15 20:29:35 +0000 | [diff] [blame] | 1050 | DRAWTEXTPARAMS dtp; |
| 1051 | |
| 1052 | memset (&dtp, 0, sizeof(dtp)); |
| 1053 | if (flags & DT_TABSTOP) |
| 1054 | { |
| 1055 | dtp.iTabLength = (flags >> 8) && 0xff; |
| 1056 | flags &= 0xffff00ff; |
| 1057 | } |
| 1058 | return DrawTextExW(hdc, (LPWSTR)str, count, rect, flags, &dtp); |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1059 | } |
| 1060 | |
| 1061 | /*********************************************************************** |
Travis Michielsen | 188b32b | 2001-07-26 20:10:40 +0000 | [diff] [blame] | 1062 | * DrawTextA (USER32.@) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1063 | */ |
Travis Michielsen | 188b32b | 2001-07-26 20:10:40 +0000 | [diff] [blame] | 1064 | INT WINAPI DrawTextA( HDC hdc, LPCSTR str, INT count, LPRECT rect, UINT flags ) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1065 | { |
Bill Medland | fd59f34 | 2002-01-15 20:29:35 +0000 | [diff] [blame] | 1066 | DRAWTEXTPARAMS dtp; |
| 1067 | |
| 1068 | memset (&dtp, 0, sizeof(dtp)); |
| 1069 | if (flags & DT_TABSTOP) |
| 1070 | { |
| 1071 | dtp.iTabLength = (flags >> 8) && 0xff; |
| 1072 | flags &= 0xffff00ff; |
| 1073 | } |
| 1074 | return DrawTextExA( hdc, (LPSTR)str, count, rect, flags, &dtp ); |
| 1075 | } |
| 1076 | |
| 1077 | /*********************************************************************** |
| 1078 | * DrawText (USER.85) |
| 1079 | */ |
| 1080 | INT16 WINAPI DrawText16( HDC16 hdc, LPCSTR str, INT16 count, LPRECT16 rect, UINT16 flags ) |
| 1081 | { |
| 1082 | INT16 ret; |
| 1083 | |
| 1084 | if (rect) |
| 1085 | { |
| 1086 | RECT rect32; |
| 1087 | CONV_RECT16TO32( rect, &rect32 ); |
| 1088 | ret = DrawTextA( hdc, str, count, &rect32, flags ); |
| 1089 | CONV_RECT32TO16( &rect32, rect ); |
| 1090 | } |
| 1091 | else ret = DrawTextA( hdc, str, count, NULL, flags); |
| 1092 | return ret; |
| 1093 | } |
| 1094 | |
| 1095 | |
| 1096 | /*********************************************************************** |
| 1097 | * |
| 1098 | * GrayString functions |
| 1099 | */ |
| 1100 | |
| 1101 | /* ### start build ### */ |
| 1102 | extern WORD CALLBACK TEXT_CallTo16_word_wlw(GRAYSTRINGPROC16,WORD,LONG,WORD); |
| 1103 | /* ### stop build ### */ |
| 1104 | |
| 1105 | struct gray_string_info |
| 1106 | { |
| 1107 | GRAYSTRINGPROC16 proc; |
| 1108 | LPARAM param; |
| 1109 | }; |
| 1110 | |
| 1111 | /* callback for 16-bit gray string proc */ |
| 1112 | static BOOL CALLBACK gray_string_callback( HDC hdc, LPARAM param, INT len ) |
| 1113 | { |
| 1114 | const struct gray_string_info *info = (struct gray_string_info *)param; |
| 1115 | return TEXT_CallTo16_word_wlw( info->proc, hdc, info->param, len ); |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1116 | } |
| 1117 | |
| 1118 | /*********************************************************************** |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1119 | * TEXT_GrayString |
| 1120 | * |
| 1121 | * FIXME: The call to 16-bit code only works because the wine GDI is a 16-bit |
| 1122 | * heap and we can guarantee that the handles fit in an INT16. We have to |
| 1123 | * rethink the strategy once the migration to NT handles is complete. |
| 1124 | * We are going to get a lot of code-duplication once this migration is |
| 1125 | * completed... |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 1126 | * |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1127 | */ |
| 1128 | static BOOL TEXT_GrayString(HDC hdc, HBRUSH hb, GRAYSTRINGPROC fn, LPARAM lp, INT len, |
| 1129 | INT x, INT y, INT cx, INT cy, BOOL unicode, BOOL _32bit) |
| 1130 | { |
| 1131 | HBITMAP hbm, hbmsave; |
| 1132 | HBRUSH hbsave; |
| 1133 | HFONT hfsave; |
Sander van Leeuwen | 500c201 | 2002-01-04 21:26:56 +0000 | [diff] [blame] | 1134 | HDC memdc; |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1135 | int slen = len; |
| 1136 | BOOL retval = TRUE; |
| 1137 | COLORREF fg, bg; |
| 1138 | |
| 1139 | if(!hdc) return FALSE; |
Sander van Leeuwen | 500c201 | 2002-01-04 21:26:56 +0000 | [diff] [blame] | 1140 | if (!(memdc = CreateCompatibleDC(hdc))) return FALSE; |
| 1141 | |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1142 | if(len == 0) |
| 1143 | { |
| 1144 | if(unicode) |
| 1145 | slen = lstrlenW((LPCWSTR)lp); |
| 1146 | else if(_32bit) |
Alexandre Julliard | cb10fda | 2000-08-06 02:41:16 +0000 | [diff] [blame] | 1147 | slen = strlen((LPCSTR)lp); |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1148 | else |
Alexandre Julliard | 982a223 | 2000-12-13 20:20:09 +0000 | [diff] [blame] | 1149 | slen = strlen(MapSL(lp)); |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1150 | } |
| 1151 | |
| 1152 | if((cx == 0 || cy == 0) && slen != -1) |
| 1153 | { |
| 1154 | SIZE s; |
| 1155 | if(unicode) |
| 1156 | GetTextExtentPoint32W(hdc, (LPCWSTR)lp, slen, &s); |
| 1157 | else if(_32bit) |
| 1158 | GetTextExtentPoint32A(hdc, (LPCSTR)lp, slen, &s); |
| 1159 | else |
Alexandre Julliard | 982a223 | 2000-12-13 20:20:09 +0000 | [diff] [blame] | 1160 | GetTextExtentPoint32A(hdc, MapSL(lp), slen, &s); |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1161 | if(cx == 0) cx = s.cx; |
| 1162 | if(cy == 0) cy = s.cy; |
| 1163 | } |
| 1164 | |
| 1165 | hbm = CreateBitmap(cx, cy, 1, 1, NULL); |
| 1166 | hbmsave = (HBITMAP)SelectObject(memdc, hbm); |
| 1167 | hbsave = SelectObject( memdc, GetStockObject(BLACK_BRUSH) ); |
| 1168 | PatBlt( memdc, 0, 0, cx, cy, PATCOPY ); |
| 1169 | SelectObject( memdc, hbsave ); |
| 1170 | SetTextColor(memdc, RGB(255, 255, 255)); |
| 1171 | SetBkColor(memdc, RGB(0, 0, 0)); |
| 1172 | hfsave = (HFONT)SelectObject(memdc, GetCurrentObject(hdc, OBJ_FONT)); |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 1173 | |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1174 | if(fn) |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 1175 | { |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1176 | if(_32bit) |
| 1177 | retval = fn(memdc, lp, slen); |
| 1178 | else |
| 1179 | retval = (BOOL)((BOOL16)((GRAYSTRINGPROC16)fn)((HDC16)memdc, lp, (INT16)slen)); |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 1180 | } |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1181 | else |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 1182 | { |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1183 | if(unicode) |
| 1184 | TextOutW(memdc, 0, 0, (LPCWSTR)lp, slen); |
| 1185 | else if(_32bit) |
| 1186 | TextOutA(memdc, 0, 0, (LPCSTR)lp, slen); |
| 1187 | else |
Alexandre Julliard | 982a223 | 2000-12-13 20:20:09 +0000 | [diff] [blame] | 1188 | TextOutA(memdc, 0, 0, MapSL(lp), slen); |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 1189 | } |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1190 | |
| 1191 | SelectObject(memdc, hfsave); |
| 1192 | |
| 1193 | /* |
| 1194 | * Windows doc says that the bitmap isn't grayed when len == -1 and |
| 1195 | * the callback function returns FALSE. However, testing this on |
| 1196 | * win95 showed otherwise... |
| 1197 | */ |
| 1198 | #ifdef GRAYSTRING_USING_DOCUMENTED_BEHAVIOUR |
| 1199 | if(retval || len != -1) |
| 1200 | #endif |
| 1201 | { |
| 1202 | hbsave = (HBRUSH)SelectObject(memdc, CACHE_GetPattern55AABrush()); |
| 1203 | PatBlt(memdc, 0, 0, cx, cy, 0x000A0329); |
| 1204 | SelectObject(memdc, hbsave); |
| 1205 | } |
| 1206 | |
| 1207 | if(hb) hbsave = (HBRUSH)SelectObject(hdc, hb); |
| 1208 | fg = SetTextColor(hdc, RGB(0, 0, 0)); |
| 1209 | bg = SetBkColor(hdc, RGB(255, 255, 255)); |
| 1210 | BitBlt(hdc, x, y, cx, cy, memdc, 0, 0, 0x00E20746); |
| 1211 | SetTextColor(hdc, fg); |
| 1212 | SetBkColor(hdc, bg); |
| 1213 | if(hb) SelectObject(hdc, hbsave); |
| 1214 | |
| 1215 | SelectObject(memdc, hbmsave); |
| 1216 | DeleteObject(hbm); |
| 1217 | DeleteDC(memdc); |
| 1218 | return retval; |
| 1219 | } |
| 1220 | |
| 1221 | |
| 1222 | /*********************************************************************** |
Patrik Stridvall | 19d66cc | 2002-01-07 21:16:46 +0000 | [diff] [blame] | 1223 | * GrayString (USER.185) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1224 | */ |
| 1225 | BOOL16 WINAPI GrayString16( HDC16 hdc, HBRUSH16 hbr, GRAYSTRINGPROC16 gsprc, |
| 1226 | LPARAM lParam, INT16 cch, INT16 x, INT16 y, |
| 1227 | INT16 cx, INT16 cy ) |
| 1228 | { |
Alexandre Julliard | 7e49205 | 2001-12-17 21:37:53 +0000 | [diff] [blame] | 1229 | struct gray_string_info info; |
| 1230 | |
| 1231 | if (!gsprc) return TEXT_GrayString(hdc, hbr, NULL, lParam, cch, x, y, cx, cy, FALSE, FALSE); |
| 1232 | info.proc = gsprc; |
| 1233 | info.param = lParam; |
| 1234 | return TEXT_GrayString( hdc, hbr, gray_string_callback, (LPARAM)&info, |
| 1235 | cch, x, y, cx, cy, FALSE, FALSE); |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1236 | } |
| 1237 | |
| 1238 | |
| 1239 | /*********************************************************************** |
Patrik Stridvall | 0c61028 | 2001-01-25 22:22:21 +0000 | [diff] [blame] | 1240 | * GrayStringA (USER32.@) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1241 | */ |
| 1242 | BOOL WINAPI GrayStringA( HDC hdc, HBRUSH hbr, GRAYSTRINGPROC gsprc, |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 1243 | LPARAM lParam, INT cch, INT x, INT y, |
| 1244 | INT cx, INT cy ) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1245 | { |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 1246 | return TEXT_GrayString(hdc, hbr, gsprc, lParam, cch, x, y, cx, cy, |
| 1247 | FALSE, TRUE); |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1248 | } |
| 1249 | |
| 1250 | |
| 1251 | /*********************************************************************** |
Patrik Stridvall | 0c61028 | 2001-01-25 22:22:21 +0000 | [diff] [blame] | 1252 | * GrayStringW (USER32.@) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1253 | */ |
| 1254 | BOOL WINAPI GrayStringW( HDC hdc, HBRUSH hbr, GRAYSTRINGPROC gsprc, |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 1255 | LPARAM lParam, INT cch, INT x, INT y, |
| 1256 | INT cx, INT cy ) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1257 | { |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 1258 | return TEXT_GrayString(hdc, hbr, gsprc, lParam, cch, x, y, cx, cy, |
| 1259 | TRUE, TRUE); |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1260 | } |
| 1261 | |
| 1262 | /*********************************************************************** |
Bill Medland | fd59f34 | 2002-01-15 20:29:35 +0000 | [diff] [blame] | 1263 | * |
| 1264 | * TabbedText functions |
| 1265 | */ |
| 1266 | |
| 1267 | /*********************************************************************** |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1268 | * TEXT_TabbedTextOut |
| 1269 | * |
| 1270 | * Helper function for TabbedTextOut() and GetTabbedTextExtent(). |
| 1271 | * Note: this doesn't work too well for text-alignment modes other |
| 1272 | * than TA_LEFT|TA_TOP. But we want bug-for-bug compatibility :-) |
| 1273 | */ |
| 1274 | static LONG TEXT_TabbedTextOut( HDC hdc, INT x, INT y, LPCSTR lpstr, |
| 1275 | INT count, INT cTabStops, const INT16 *lpTabPos16, |
| 1276 | const INT *lpTabPos32, INT nTabOrg, |
| 1277 | BOOL fDisplayText ) |
| 1278 | { |
| 1279 | INT defWidth; |
| 1280 | SIZE extent; |
| 1281 | int i, tabPos = x; |
| 1282 | int start = x; |
| 1283 | |
| 1284 | extent.cx = 0; |
| 1285 | extent.cy = 0; |
| 1286 | |
| 1287 | if (cTabStops == 1) |
| 1288 | { |
| 1289 | defWidth = lpTabPos32 ? *lpTabPos32 : *lpTabPos16; |
| 1290 | cTabStops = 0; |
| 1291 | } |
| 1292 | else |
| 1293 | { |
| 1294 | TEXTMETRICA tm; |
| 1295 | GetTextMetricsA( hdc, &tm ); |
| 1296 | defWidth = 8 * tm.tmAveCharWidth; |
| 1297 | } |
| 1298 | |
| 1299 | while (count > 0) |
| 1300 | { |
| 1301 | for (i = 0; i < count; i++) |
| 1302 | if (lpstr[i] == '\t') break; |
| 1303 | GetTextExtentPointA( hdc, lpstr, i, &extent ); |
| 1304 | if (lpTabPos32) |
| 1305 | { |
| 1306 | while ((cTabStops > 0) && |
| 1307 | (nTabOrg + *lpTabPos32 <= x + extent.cx)) |
| 1308 | { |
| 1309 | lpTabPos32++; |
| 1310 | cTabStops--; |
| 1311 | } |
| 1312 | } |
| 1313 | else |
| 1314 | { |
| 1315 | while ((cTabStops > 0) && |
| 1316 | (nTabOrg + *lpTabPos16 <= x + extent.cx)) |
| 1317 | { |
| 1318 | lpTabPos16++; |
| 1319 | cTabStops--; |
| 1320 | } |
| 1321 | } |
| 1322 | if (i == count) |
| 1323 | tabPos = x + extent.cx; |
| 1324 | else if (cTabStops > 0) |
| 1325 | tabPos = nTabOrg + (lpTabPos32 ? *lpTabPos32 : *lpTabPos16); |
| 1326 | else |
| 1327 | tabPos = nTabOrg + ((x + extent.cx - nTabOrg) / defWidth + 1) * defWidth; |
| 1328 | if (fDisplayText) |
| 1329 | { |
| 1330 | RECT r; |
| 1331 | r.left = x; |
| 1332 | r.top = y; |
| 1333 | r.right = tabPos; |
| 1334 | r.bottom = y + extent.cy; |
| 1335 | ExtTextOutA( hdc, x, y, |
| 1336 | GetBkMode(hdc) == OPAQUE ? ETO_OPAQUE : 0, |
| 1337 | &r, lpstr, i, NULL ); |
| 1338 | } |
| 1339 | x = tabPos; |
| 1340 | count -= i+1; |
| 1341 | lpstr += i+1; |
| 1342 | } |
| 1343 | return MAKELONG(tabPos - start, extent.cy); |
| 1344 | } |
| 1345 | |
| 1346 | |
| 1347 | /*********************************************************************** |
Patrik Stridvall | 01d5e5b | 2001-07-02 19:59:40 +0000 | [diff] [blame] | 1348 | * TabbedTextOut (USER.196) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1349 | */ |
| 1350 | LONG WINAPI TabbedTextOut16( HDC16 hdc, INT16 x, INT16 y, LPCSTR lpstr, |
| 1351 | INT16 count, INT16 cTabStops, |
| 1352 | const INT16 *lpTabPos, INT16 nTabOrg ) |
| 1353 | { |
Andreas Mohr | 4fb9c09 | 2001-06-08 20:19:28 +0000 | [diff] [blame] | 1354 | TRACE("%04x %d,%d %s %d\n", hdc, x, y, debugstr_an(lpstr,count), count ); |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1355 | return TEXT_TabbedTextOut( hdc, x, y, lpstr, count, cTabStops, |
| 1356 | lpTabPos, NULL, nTabOrg, TRUE ); |
| 1357 | } |
| 1358 | |
| 1359 | |
| 1360 | /*********************************************************************** |
Patrik Stridvall | 0c61028 | 2001-01-25 22:22:21 +0000 | [diff] [blame] | 1361 | * TabbedTextOutA (USER32.@) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1362 | */ |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 1363 | LONG WINAPI TabbedTextOutA( HDC hdc, INT x, INT y, LPCSTR lpstr, INT count, |
| 1364 | INT cTabStops, const INT *lpTabPos, INT nTabOrg ) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1365 | { |
Andreas Mohr | 4fb9c09 | 2001-06-08 20:19:28 +0000 | [diff] [blame] | 1366 | TRACE("%04x %d,%d %s %d\n", hdc, x, y, debugstr_an(lpstr,count), count ); |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1367 | return TEXT_TabbedTextOut( hdc, x, y, lpstr, count, cTabStops, |
| 1368 | NULL, lpTabPos, nTabOrg, TRUE ); |
| 1369 | } |
| 1370 | |
| 1371 | |
| 1372 | /*********************************************************************** |
Patrik Stridvall | 0c61028 | 2001-01-25 22:22:21 +0000 | [diff] [blame] | 1373 | * TabbedTextOutW (USER32.@) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1374 | */ |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 1375 | LONG WINAPI TabbedTextOutW( HDC hdc, INT x, INT y, LPCWSTR str, INT count, |
| 1376 | INT cTabStops, const INT *lpTabPos, INT nTabOrg ) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1377 | { |
| 1378 | LONG ret; |
| 1379 | LPSTR p; |
| 1380 | INT acount; |
| 1381 | UINT codepage = CP_ACP; /* FIXME: get codepage of font charset */ |
| 1382 | |
| 1383 | acount = WideCharToMultiByte(codepage,0,str,count,NULL,0,NULL,NULL); |
| 1384 | p = HeapAlloc( GetProcessHeap(), 0, acount ); |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 1385 | if(p == NULL) return 0; /* FIXME: is this the correct return on failure */ |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1386 | acount = WideCharToMultiByte(codepage,0,str,count,p,acount,NULL,NULL); |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 1387 | ret = TabbedTextOutA( hdc, x, y, p, acount, cTabStops, lpTabPos, nTabOrg ); |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1388 | HeapFree( GetProcessHeap(), 0, p ); |
| 1389 | return ret; |
| 1390 | } |
| 1391 | |
| 1392 | |
| 1393 | /*********************************************************************** |
Patrik Stridvall | 01d5e5b | 2001-07-02 19:59:40 +0000 | [diff] [blame] | 1394 | * GetTabbedTextExtent (USER.197) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1395 | */ |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 1396 | DWORD WINAPI GetTabbedTextExtent16( HDC16 hdc, LPCSTR lpstr, INT16 count, |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1397 | INT16 cTabStops, const INT16 *lpTabPos ) |
| 1398 | { |
Andreas Mohr | 4fb9c09 | 2001-06-08 20:19:28 +0000 | [diff] [blame] | 1399 | TRACE("%04x %s %d\n", hdc, debugstr_an(lpstr,count), count ); |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1400 | return TEXT_TabbedTextOut( hdc, 0, 0, lpstr, count, cTabStops, |
| 1401 | lpTabPos, NULL, 0, FALSE ); |
| 1402 | } |
| 1403 | |
| 1404 | |
| 1405 | /*********************************************************************** |
Patrik Stridvall | 0c61028 | 2001-01-25 22:22:21 +0000 | [diff] [blame] | 1406 | * GetTabbedTextExtentA (USER32.@) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1407 | */ |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 1408 | DWORD WINAPI GetTabbedTextExtentA( HDC hdc, LPCSTR lpstr, INT count, |
| 1409 | INT cTabStops, const INT *lpTabPos ) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1410 | { |
Andreas Mohr | a49b5be | 2001-07-17 00:51:00 +0000 | [diff] [blame] | 1411 | TRACE("%04x %s %d\n", hdc, debugstr_an(lpstr,count), count ); |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1412 | return TEXT_TabbedTextOut( hdc, 0, 0, lpstr, count, cTabStops, |
| 1413 | NULL, lpTabPos, 0, FALSE ); |
| 1414 | } |
| 1415 | |
| 1416 | |
| 1417 | /*********************************************************************** |
Patrik Stridvall | 0c61028 | 2001-01-25 22:22:21 +0000 | [diff] [blame] | 1418 | * GetTabbedTextExtentW (USER32.@) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1419 | */ |
Dimitrie O. Paun | 981a9a4 | 2000-12-12 00:35:54 +0000 | [diff] [blame] | 1420 | DWORD WINAPI GetTabbedTextExtentW( HDC hdc, LPCWSTR lpstr, INT count, |
| 1421 | INT cTabStops, const INT *lpTabPos ) |
Alexandre Julliard | 93652e1 | 2000-08-04 04:21:02 +0000 | [diff] [blame] | 1422 | { |
| 1423 | LONG ret; |
| 1424 | LPSTR p; |
| 1425 | INT acount; |
| 1426 | UINT codepage = CP_ACP; /* FIXME: get codepage of font charset */ |
| 1427 | |
| 1428 | acount = WideCharToMultiByte(codepage,0,lpstr,count,NULL,0,NULL,NULL); |
| 1429 | p = HeapAlloc( GetProcessHeap(), 0, acount ); |
| 1430 | if(p == NULL) return 0; /* FIXME: is this the correct failure value? */ |
| 1431 | acount = WideCharToMultiByte(codepage,0,lpstr,count,p,acount,NULL,NULL); |
| 1432 | ret = GetTabbedTextExtentA( hdc, p, acount, cTabStops, lpTabPos ); |
| 1433 | HeapFree( GetProcessHeap(), 0, p ); |
| 1434 | return ret; |
| 1435 | } |