gdi32: Use NtGdiGetCharABCWidthsW for GetCharABCWidthsI.
[wine.git] / dlls / gdi32 / text.c
blob1238a8f9f45f73c446d9869862b595b1d6b06a4b
1 /*
2 * GDI text handling
4 * Copyright 1993 Alexandre Julliard
5 * Copyright 1997 Alex Korobka
6 * Copyright 2002,2003 Shachar Shemesh
7 * Copyright 2007 Maarten Lankhorst
8 * Copyright 2010 CodeWeavers, Aric Stewart
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 * Code derived from the modified reference implementation
25 * that was found in revision 17 of http://unicode.org/reports/tr9/
26 * "Unicode Standard Annex #9: THE BIDIRECTIONAL ALGORITHM"
28 * -- Copyright (C) 1999-2005, ASMUS, Inc.
30 * Permission is hereby granted, free of charge, to any person obtaining a
31 * copy of the Unicode data files and any associated documentation (the
32 * "Data Files") or Unicode software and any associated documentation (the
33 * "Software") to deal in the Data Files or Software without restriction,
34 * including without limitation the rights to use, copy, modify, merge,
35 * publish, distribute, and/or sell copies of the Data Files or Software,
36 * and to permit persons to whom the Data Files or Software are furnished
37 * to do so, provided that (a) the above copyright notice(s) and this
38 * permission notice appear with all copies of the Data Files or Software,
39 * (b) both the above copyright notice(s) and this permission notice appear
40 * in associated documentation, and (c) there is clear notice in each
41 * modified Data File or in the Software as well as in the documentation
42 * associated with the Data File(s) or Software that the data or software
43 * has been modified.
46 #include <stdarg.h>
47 #include <limits.h>
48 #include <assert.h>
50 #include "windef.h"
51 #include "winbase.h"
52 #include "wingdi.h"
53 #include "winnls.h"
54 #include "usp10.h"
55 #include "wine/debug.h"
56 #include "gdi_private.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(bidi);
60 /* HELPER FUNCTIONS AND DECLARATIONS */
62 /* Wine_GCPW Flags */
63 /* Directionality -
64 * LOOSE means taking the directionality of the first strong character, if there is found one.
65 * FORCE means the paragraph direction is forced. (RLE/LRE)
67 #define WINE_GCPW_FORCE_LTR 0
68 #define WINE_GCPW_FORCE_RTL 1
69 #define WINE_GCPW_LOOSE_LTR 2
70 #define WINE_GCPW_LOOSE_RTL 3
71 #define WINE_GCPW_DIR_MASK 3
72 #define WINE_GCPW_LOOSE_MASK 2
74 #define odd(x) ((x) & 1)
76 extern const unsigned short bidi_direction_table[] DECLSPEC_HIDDEN;
78 /*------------------------------------------------------------------------
79 Bidirectional Character Types
81 as defined by the Unicode Bidirectional Algorithm Table 3-7.
83 Note:
85 The list of bidirectional character types here is not grouped the
86 same way as the table 3-7, since the numeric values for the types
87 are chosen to keep the state and action tables compact.
88 ------------------------------------------------------------------------*/
89 enum directions
91 /* input types */
92 /* ON MUST be zero, code relies on ON = N = 0 */
93 ON = 0, /* Other Neutral */
94 L, /* Left Letter */
95 R, /* Right Letter */
96 AN, /* Arabic Number */
97 EN, /* European Number */
98 AL, /* Arabic Letter (Right-to-left) */
99 NSM, /* Non-spacing Mark */
100 CS, /* Common Separator */
101 ES, /* European Separator */
102 ET, /* European Terminator (post/prefix e.g. $ and %) */
104 /* resolved types */
105 BN, /* Boundary neutral (type of RLE etc after explicit levels) */
107 /* input types, */
108 S, /* Segment Separator (TAB) // used only in L1 */
109 WS, /* White space // used only in L1 */
110 B, /* Paragraph Separator (aka as PS) */
112 /* types for explicit controls */
113 RLO, /* these are used only in X1-X9 */
114 RLE,
115 LRO,
116 LRE,
117 PDF,
119 LRI, /* Isolate formatting characters new with 6.3 */
120 RLI,
121 FSI,
122 PDI,
124 /* resolved types, also resolved directions */
125 NI = ON, /* alias, where ON, WS and S are treated the same */
128 /* HELPER FUNCTIONS */
130 static inline unsigned short get_table_entry(const unsigned short *table, WCHAR ch)
132 return table[table[table[ch >> 8] + ((ch >> 4) & 0x0f)] + (ch & 0xf)];
135 /* Convert the libwine information to the direction enum */
136 static void classify(LPCWSTR lpString, WORD *chartype, DWORD uCount)
138 unsigned i;
140 for (i = 0; i < uCount; ++i)
141 chartype[i] = get_table_entry( bidi_direction_table, lpString[i] );
144 /* Set a run of cval values at locations all prior to, but not including */
145 /* iStart, to the new value nval. */
146 static void SetDeferredRun(BYTE *pval, int cval, int iStart, int nval)
148 int i = iStart - 1;
149 for (; i >= iStart - cval; i--)
151 pval[i] = nval;
155 /* THE PARAGRAPH LEVEL */
157 /*------------------------------------------------------------------------
158 Function: resolveParagraphs
160 Resolves the input strings into blocks over which the algorithm
161 is then applied.
163 Implements Rule P1 of the Unicode Bidi Algorithm
165 Input: Text string
166 Character count
168 Output: revised character count
170 Note: This is a very simplistic function. In effect it restricts
171 the action of the algorithm to the first paragraph in the input
172 where a paragraph ends at the end of the first block separator
173 or at the end of the input text.
175 ------------------------------------------------------------------------*/
177 static int resolveParagraphs(WORD *types, int cch)
179 /* skip characters not of type B */
180 int ich = 0;
181 for(; ich < cch && types[ich] != B; ich++);
182 /* stop after first B, make it a BN for use in the next steps */
183 if (ich < cch && types[ich] == B)
184 types[ich++] = BN;
185 return ich;
188 /* REORDER */
189 /*------------------------------------------------------------------------
190 Function: resolveLines
192 Breaks a paragraph into lines
194 Input: Array of line break flags
195 Character count
196 In/Out: Array of characters
198 Returns the count of characters on the first line
200 Note: This function only breaks lines at hard line breaks. Other
201 line breaks can be passed in. If pbrk[n] is TRUE, then a break
202 occurs after the character in pszInput[n]. Breaks before the first
203 character are not allowed.
204 ------------------------------------------------------------------------*/
205 static int resolveLines(LPCWSTR pszInput, const BOOL * pbrk, int cch)
207 /* skip characters not of type LS */
208 int ich = 0;
209 for(; ich < cch; ich++)
211 if (pszInput[ich] == (WCHAR)'\n' || (pbrk && pbrk[ich]))
213 ich++;
214 break;
218 return ich;
221 /*------------------------------------------------------------------------
222 Function: resolveWhiteSpace
224 Resolves levels for WS and S
225 Implements rule L1 of the Unicode bidi Algorithm.
227 Input: Base embedding level
228 Character count
229 Array of direction classes (for one line of text)
231 In/Out: Array of embedding levels (for one line of text)
233 Note: this should be applied a line at a time. The default driver
234 code supplied in this file assumes a single line of text; for
235 a real implementation, cch and the initial pointer values
236 would have to be adjusted.
237 ------------------------------------------------------------------------*/
238 static void resolveWhitespace(int baselevel, const WORD *pcls, BYTE *plevel, int cch)
240 int cchrun = 0;
241 BYTE oldlevel = baselevel;
243 int ich = 0;
244 for (; ich < cch; ich++)
246 switch(pcls[ich])
248 default:
249 cchrun = 0; /* any other character breaks the run */
250 break;
251 case WS:
252 cchrun++;
253 break;
255 case RLE:
256 case LRE:
257 case LRO:
258 case RLO:
259 case PDF:
260 case LRI:
261 case RLI:
262 case FSI:
263 case PDI:
264 case BN:
265 plevel[ich] = oldlevel;
266 cchrun++;
267 break;
269 case S:
270 case B:
271 /* reset levels for WS before eot */
272 SetDeferredRun(plevel, cchrun, ich, baselevel);
273 cchrun = 0;
274 plevel[ich] = baselevel;
275 break;
277 oldlevel = plevel[ich];
279 /* reset level before eot */
280 SetDeferredRun(plevel, cchrun, ich, baselevel);
283 /*------------------------------------------------------------------------
284 Function: BidiLines
286 Implements the Line-by-Line phases of the Unicode Bidi Algorithm
288 Input: Count of characters
289 Array of character directions
291 Inp/Out: Input text
292 Array of levels
294 ------------------------------------------------------------------------*/
295 static void BidiLines(int baselevel, LPWSTR pszOutLine, LPCWSTR pszLine, const WORD * pclsLine,
296 BYTE * plevelLine, int cchPara, const BOOL * pbrk)
298 int cchLine = 0;
299 int done = 0;
300 int *run;
302 run = HeapAlloc(GetProcessHeap(), 0, cchPara * sizeof(int));
303 if (!run)
305 WARN("Out of memory\n");
306 return;
311 /* break lines at LS */
312 cchLine = resolveLines(pszLine, pbrk, cchPara);
314 /* resolve whitespace */
315 resolveWhitespace(baselevel, pclsLine, plevelLine, cchLine);
317 if (pszOutLine)
319 int i;
320 /* reorder each line in place */
321 ScriptLayout(cchLine, plevelLine, NULL, run);
322 for (i = 0; i < cchLine; i++)
323 pszOutLine[done+run[i]] = pszLine[i];
326 pszLine += cchLine;
327 plevelLine += cchLine;
328 pbrk += pbrk ? cchLine : 0;
329 pclsLine += cchLine;
330 cchPara -= cchLine;
331 done += cchLine;
333 } while (cchPara);
335 HeapFree(GetProcessHeap(), 0, run);
338 /*************************************************************
339 * BIDI_Reorder
341 * Returns TRUE if reordering was required and done.
343 static BOOL BIDI_Reorder( HDC hDC, /* [in] Display DC */
344 LPCWSTR lpString, /* [in] The string for which information is to be returned */
345 INT uCount, /* [in] Number of WCHARs in string. */
346 DWORD dwFlags, /* [in] GetCharacterPlacement compatible flags */
347 DWORD dwWineGCP_Flags, /* [in] Wine internal flags - Force paragraph direction */
348 LPWSTR lpOutString, /* [out] Reordered string */
349 INT uCountOut, /* [in] Size of output buffer */
350 UINT *lpOrder, /* [out] Logical -> Visual order map */
351 WORD **lpGlyphs, /* [out] reordered, mirrored, shaped glyphs to display */
352 INT *cGlyphs ) /* [out] number of glyphs generated */
354 WORD *chartype = NULL;
355 BYTE *levels = NULL;
356 INT i, done;
357 unsigned glyph_i;
358 BOOL is_complex, ret = FALSE;
360 int maxItems;
361 int nItems;
362 SCRIPT_CONTROL Control;
363 SCRIPT_STATE State;
364 SCRIPT_ITEM *pItems = NULL;
365 HRESULT res;
366 SCRIPT_CACHE psc = NULL;
367 WORD *run_glyphs = NULL;
368 WORD *pwLogClust = NULL;
369 SCRIPT_VISATTR *psva = NULL;
370 DWORD cMaxGlyphs = 0;
371 BOOL doGlyphs = TRUE;
373 TRACE("%s, %d, 0x%08x lpOutString=%p, lpOrder=%p\n",
374 debugstr_wn(lpString, uCount), uCount, dwFlags,
375 lpOutString, lpOrder);
377 memset(&Control, 0, sizeof(Control));
378 memset(&State, 0, sizeof(State));
379 if (lpGlyphs)
380 *lpGlyphs = NULL;
382 if (!(dwFlags & GCP_REORDER))
384 FIXME("Asked to reorder without reorder flag set\n");
385 return FALSE;
388 if (lpOutString && uCountOut < uCount)
390 FIXME("lpOutString too small\n");
391 return FALSE;
394 chartype = HeapAlloc(GetProcessHeap(), 0, uCount * sizeof(WORD));
395 if (!chartype)
397 WARN("Out of memory\n");
398 return FALSE;
401 if (lpOutString)
402 memcpy(lpOutString, lpString, uCount * sizeof(WCHAR));
404 is_complex = FALSE;
405 for (i = 0; i < uCount && !is_complex; i++)
407 if ((lpString[i] >= 0x900 && lpString[i] <= 0xfff) ||
408 (lpString[i] >= 0x1cd0 && lpString[i] <= 0x1cff) ||
409 (lpString[i] >= 0xa840 && lpString[i] <= 0xa8ff))
410 is_complex = TRUE;
413 /* Verify reordering will be required */
414 if ((WINE_GCPW_FORCE_RTL == (dwWineGCP_Flags&WINE_GCPW_DIR_MASK)) ||
415 ((dwWineGCP_Flags&WINE_GCPW_DIR_MASK) == WINE_GCPW_LOOSE_RTL))
416 State.uBidiLevel = 1;
417 else if (!is_complex)
419 done = 1;
420 classify(lpString, chartype, uCount);
421 for (i = 0; i < uCount; i++)
422 switch (chartype[i])
424 case R:
425 case AL:
426 case RLE:
427 case RLO:
428 done = 0;
429 break;
431 if (done)
433 HeapFree(GetProcessHeap(), 0, chartype);
434 if (lpOrder)
436 for (i = 0; i < uCount; i++)
437 lpOrder[i] = i;
439 return TRUE;
443 levels = HeapAlloc(GetProcessHeap(), 0, uCount * sizeof(BYTE));
444 if (!levels)
446 WARN("Out of memory\n");
447 goto cleanup;
450 maxItems = 5;
451 pItems = HeapAlloc(GetProcessHeap(),0, maxItems * sizeof(SCRIPT_ITEM));
452 if (!pItems)
454 WARN("Out of memory\n");
455 goto cleanup;
458 if (lpGlyphs)
460 cMaxGlyphs = 1.5 * uCount + 16;
461 run_glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD) * cMaxGlyphs);
462 if (!run_glyphs)
464 WARN("Out of memory\n");
465 goto cleanup;
467 pwLogClust = HeapAlloc(GetProcessHeap(),0,sizeof(WORD) * uCount);
468 if (!pwLogClust)
470 WARN("Out of memory\n");
471 goto cleanup;
473 psva = HeapAlloc(GetProcessHeap(),0,sizeof(SCRIPT_VISATTR) * uCount);
474 if (!psva)
476 WARN("Out of memory\n");
477 goto cleanup;
481 done = 0;
482 glyph_i = 0;
483 while (done < uCount)
485 INT j;
486 classify(lpString + done, chartype, uCount - done);
487 /* limit text to first block */
488 i = resolveParagraphs(chartype, uCount - done);
489 for (j = 0; j < i; ++j)
490 switch(chartype[j])
492 case B:
493 case S:
494 case WS:
495 case ON: chartype[j] = NI;
496 default: continue;
499 if ((dwWineGCP_Flags&WINE_GCPW_DIR_MASK) == WINE_GCPW_LOOSE_RTL)
500 State.uBidiLevel = 1;
501 else if ((dwWineGCP_Flags&WINE_GCPW_DIR_MASK) == WINE_GCPW_LOOSE_LTR)
502 State.uBidiLevel = 0;
504 if (dwWineGCP_Flags & WINE_GCPW_LOOSE_MASK)
506 for (j = 0; j < i; ++j)
507 if (chartype[j] == L)
509 State.uBidiLevel = 0;
510 break;
512 else if (chartype[j] == R || chartype[j] == AL)
514 State.uBidiLevel = 1;
515 break;
519 res = ScriptItemize(lpString + done, i, maxItems, &Control, &State, pItems, &nItems);
520 while (res == E_OUTOFMEMORY)
522 SCRIPT_ITEM *new_pItems = HeapReAlloc(GetProcessHeap(), 0, pItems, sizeof(*pItems) * maxItems * 2);
523 if (!new_pItems)
525 WARN("Out of memory\n");
526 goto cleanup;
528 pItems = new_pItems;
529 maxItems *= 2;
530 res = ScriptItemize(lpString + done, i, maxItems, &Control, &State, pItems, &nItems);
533 if (lpOutString || lpOrder)
534 for (j = 0; j < nItems; j++)
536 int k;
537 for (k = pItems[j].iCharPos; k < pItems[j+1].iCharPos; k++)
538 levels[k] = pItems[j].a.s.uBidiLevel;
541 if (lpOutString)
543 /* assign directional types again, but for WS, S this time */
544 classify(lpString + done, chartype, i);
546 BidiLines(State.uBidiLevel, lpOutString + done, lpString + done,
547 chartype, levels, i, 0);
550 if (lpOrder)
552 int k, lastgood;
553 for (j = lastgood = 0; j < i; ++j)
554 if (levels[j] != levels[lastgood])
556 --j;
557 if (odd(levels[lastgood]))
558 for (k = j; k >= lastgood; --k)
559 lpOrder[done + k] = done + j - k;
560 else
561 for (k = lastgood; k <= j; ++k)
562 lpOrder[done + k] = done + k;
563 lastgood = ++j;
565 if (odd(levels[lastgood]))
566 for (k = j - 1; k >= lastgood; --k)
567 lpOrder[done + k] = done + j - 1 - k;
568 else
569 for (k = lastgood; k < j; ++k)
570 lpOrder[done + k] = done + k;
573 if (lpGlyphs && doGlyphs)
575 BYTE *runOrder;
576 int *visOrder;
577 SCRIPT_ITEM *curItem;
579 runOrder = HeapAlloc(GetProcessHeap(), 0, maxItems * sizeof(*runOrder));
580 visOrder = HeapAlloc(GetProcessHeap(), 0, maxItems * sizeof(*visOrder));
581 if (!runOrder || !visOrder)
583 WARN("Out of memory\n");
584 HeapFree(GetProcessHeap(), 0, runOrder);
585 HeapFree(GetProcessHeap(), 0, visOrder);
586 goto cleanup;
589 for (j = 0; j < nItems; j++)
590 runOrder[j] = pItems[j].a.s.uBidiLevel;
592 ScriptLayout(nItems, runOrder, visOrder, NULL);
594 for (j = 0; j < nItems; j++)
596 int k;
597 int cChars,cOutGlyphs;
598 curItem = &pItems[visOrder[j]];
600 cChars = pItems[visOrder[j]+1].iCharPos - curItem->iCharPos;
602 res = ScriptShape(hDC, &psc, lpString + done + curItem->iCharPos, cChars, cMaxGlyphs, &curItem->a, run_glyphs, pwLogClust, psva, &cOutGlyphs);
603 while (res == E_OUTOFMEMORY)
605 WORD *new_run_glyphs = HeapReAlloc(GetProcessHeap(), 0, run_glyphs, sizeof(*run_glyphs) * cMaxGlyphs * 2);
606 if (!new_run_glyphs)
608 WARN("Out of memory\n");
609 HeapFree(GetProcessHeap(), 0, runOrder);
610 HeapFree(GetProcessHeap(), 0, visOrder);
611 HeapFree(GetProcessHeap(), 0, *lpGlyphs);
612 *lpGlyphs = NULL;
613 goto cleanup;
615 run_glyphs = new_run_glyphs;
616 cMaxGlyphs *= 2;
617 res = ScriptShape(hDC, &psc, lpString + done + curItem->iCharPos, cChars, cMaxGlyphs, &curItem->a, run_glyphs, pwLogClust, psva, &cOutGlyphs);
619 if (res)
621 if (res == USP_E_SCRIPT_NOT_IN_FONT)
622 TRACE("Unable to shape with currently selected font\n");
623 else
624 FIXME("Unable to shape string (%x)\n",res);
625 j = nItems;
626 doGlyphs = FALSE;
627 HeapFree(GetProcessHeap(), 0, *lpGlyphs);
628 *lpGlyphs = NULL;
630 else
632 WORD *new_glyphs;
633 if (*lpGlyphs)
634 new_glyphs = HeapReAlloc(GetProcessHeap(), 0, *lpGlyphs, sizeof(**lpGlyphs) * (glyph_i + cOutGlyphs));
635 else
636 new_glyphs = HeapAlloc(GetProcessHeap(), 0, sizeof(**lpGlyphs) * (glyph_i + cOutGlyphs));
637 if (!new_glyphs)
639 WARN("Out of memory\n");
640 HeapFree(GetProcessHeap(), 0, runOrder);
641 HeapFree(GetProcessHeap(), 0, visOrder);
642 HeapFree(GetProcessHeap(), 0, *lpGlyphs);
643 *lpGlyphs = NULL;
644 goto cleanup;
646 *lpGlyphs = new_glyphs;
647 for (k = 0; k < cOutGlyphs; k++)
648 (*lpGlyphs)[glyph_i+k] = run_glyphs[k];
649 glyph_i += cOutGlyphs;
652 HeapFree(GetProcessHeap(), 0, runOrder);
653 HeapFree(GetProcessHeap(), 0, visOrder);
656 done += i;
658 if (cGlyphs)
659 *cGlyphs = glyph_i;
661 ret = TRUE;
662 cleanup:
663 HeapFree(GetProcessHeap(), 0, chartype);
664 HeapFree(GetProcessHeap(), 0, levels);
665 HeapFree(GetProcessHeap(), 0, pItems);
666 HeapFree(GetProcessHeap(), 0, run_glyphs);
667 HeapFree(GetProcessHeap(), 0, pwLogClust);
668 HeapFree(GetProcessHeap(), 0, psva);
669 ScriptFreeCache(&psc);
670 return ret;
673 /***********************************************************************
674 * text_mbtowc
676 * Returns a Unicode translation of str using the charset of the
677 * currently selected font in hdc. If count is -1 then str is assumed
678 * to be '\0' terminated, otherwise it contains the number of bytes to
679 * convert. If plenW is non-NULL, on return it will point to the
680 * number of WCHARs that have been written. If ret_cp is non-NULL, on
681 * return it will point to the codepage used in the conversion. The
682 * caller should free the returned string from the process heap
683 * itself.
685 static WCHAR *text_mbtowc( HDC hdc, const char *str, INT count, INT *plenW, UINT *ret_cp )
687 UINT cp;
688 INT lenW;
689 LPWSTR strW;
691 cp = GdiGetCodePage( hdc );
693 if (count == -1) count = strlen( str );
694 lenW = MultiByteToWideChar( cp, 0, str, count, NULL, 0 );
695 strW = HeapAlloc( GetProcessHeap(), 0, lenW * sizeof(WCHAR) );
696 MultiByteToWideChar( cp, 0, str, count, strW, lenW );
697 TRACE( "mapped %s -> %s\n", debugstr_an(str, count), debugstr_wn(strW, lenW) );
698 if (plenW) *plenW = lenW;
699 if (ret_cp) *ret_cp = cp;
700 return strW;
703 static void text_metric_WtoA( const TEXTMETRICW *tmW, TEXTMETRICA *tmA )
705 tmA->tmHeight = tmW->tmHeight;
706 tmA->tmAscent = tmW->tmAscent;
707 tmA->tmDescent = tmW->tmDescent;
708 tmA->tmInternalLeading = tmW->tmInternalLeading;
709 tmA->tmExternalLeading = tmW->tmExternalLeading;
710 tmA->tmAveCharWidth = tmW->tmAveCharWidth;
711 tmA->tmMaxCharWidth = tmW->tmMaxCharWidth;
712 tmA->tmWeight = tmW->tmWeight;
713 tmA->tmOverhang = tmW->tmOverhang;
714 tmA->tmDigitizedAspectX = tmW->tmDigitizedAspectX;
715 tmA->tmDigitizedAspectY = tmW->tmDigitizedAspectY;
716 tmA->tmFirstChar = min( tmW->tmFirstChar, 255 );
717 if (tmW->tmCharSet == SYMBOL_CHARSET)
719 tmA->tmFirstChar = 0x1e;
720 tmA->tmLastChar = 0xff; /* win9x behaviour - we need the OS2 table data to calculate correctly */
722 else if (tmW->tmPitchAndFamily & TMPF_TRUETYPE)
724 tmA->tmFirstChar = tmW->tmDefaultChar - 1;
725 tmA->tmLastChar = min( tmW->tmLastChar, 0xff );
727 else
729 tmA->tmFirstChar = min( tmW->tmFirstChar, 0xff );
730 tmA->tmLastChar = min( tmW->tmLastChar, 0xff );
732 tmA->tmDefaultChar = tmW->tmDefaultChar;
733 tmA->tmBreakChar = tmW->tmBreakChar;
734 tmA->tmItalic = tmW->tmItalic;
735 tmA->tmUnderlined = tmW->tmUnderlined;
736 tmA->tmStruckOut = tmW->tmStruckOut;
737 tmA->tmPitchAndFamily = tmW->tmPitchAndFamily;
738 tmA->tmCharSet = tmW->tmCharSet;
741 static void logfont_AtoW( const LOGFONTA *fontA, LPLOGFONTW fontW )
743 memcpy( fontW, fontA, sizeof(LOGFONTA) - LF_FACESIZE );
744 MultiByteToWideChar( CP_ACP, 0, fontA->lfFaceName, -1, fontW->lfFaceName,
745 LF_FACESIZE );
746 fontW->lfFaceName[LF_FACESIZE - 1] = 0;
749 static void logfontex_AtoW( const ENUMLOGFONTEXA *fontA, LPENUMLOGFONTEXW fontW )
751 logfont_AtoW( &fontA->elfLogFont, &fontW->elfLogFont );
753 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfFullName, -1,
754 fontW->elfFullName, LF_FULLFACESIZE );
755 fontW->elfFullName[LF_FULLFACESIZE - 1] = '\0';
756 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfStyle, -1,
757 fontW->elfStyle, LF_FACESIZE );
758 fontW->elfStyle[LF_FACESIZE - 1] = '\0';
759 MultiByteToWideChar( CP_ACP, 0, (LPCSTR)fontA->elfScript, -1,
760 fontW->elfScript, LF_FACESIZE );
761 fontW->elfScript[LF_FACESIZE - 1] = '\0';
764 /***********************************************************************
765 * GdiGetCodePage (GDI32.@)
767 DWORD WINAPI GdiGetCodePage( HDC hdc )
769 DC_ATTR *dc_attr = get_dc_attr( hdc );
770 return dc_attr ? dc_attr->font_code_page : CP_ACP;
773 /***********************************************************************
774 * CreateFontIndirectExA (GDI32.@)
776 HFONT WINAPI CreateFontIndirectExA( const ENUMLOGFONTEXDVA *enumexA )
778 ENUMLOGFONTEXDVW enumexW;
780 if (!enumexA) return 0;
782 logfontex_AtoW( &enumexA->elfEnumLogfontEx, &enumexW.elfEnumLogfontEx );
783 enumexW.elfDesignVector = enumexA->elfDesignVector;
784 return CreateFontIndirectExW( &enumexW );
787 /***********************************************************************
788 * CreateFontIndirectExW (GDI32.@)
790 HFONT WINAPI CreateFontIndirectExW( const ENUMLOGFONTEXDVW *enumex )
792 return NtGdiHfontCreate( enumex, sizeof(*enumex), 0, 0, NULL );
795 /***********************************************************************
796 * CreateFontIndirectA (GDI32.@)
798 HFONT WINAPI CreateFontIndirectA( const LOGFONTA *lfA )
800 LOGFONTW lfW;
802 if (!lfA) return 0;
804 logfont_AtoW( lfA, &lfW );
805 return CreateFontIndirectW( &lfW );
808 /***********************************************************************
809 * CreateFontIndirectW (GDI32.@)
811 HFONT WINAPI CreateFontIndirectW( const LOGFONTW *lf )
813 ENUMLOGFONTEXDVW exdv;
815 if (!lf) return 0;
817 exdv.elfEnumLogfontEx.elfLogFont = *lf;
818 exdv.elfEnumLogfontEx.elfFullName[0] = 0;
819 exdv.elfEnumLogfontEx.elfStyle[0] = 0;
820 exdv.elfEnumLogfontEx.elfScript[0] = 0;
821 return CreateFontIndirectExW( &exdv );
824 /*************************************************************************
825 * CreateFontA (GDI32.@)
827 HFONT WINAPI CreateFontA( INT height, INT width, INT esc, INT orient, INT weight,
828 DWORD italic, DWORD underline, DWORD strikeout,
829 DWORD charset, DWORD outpres, DWORD clippres,
830 DWORD quality, DWORD pitch, const char *name )
832 LOGFONTA logfont;
834 logfont.lfHeight = height;
835 logfont.lfWidth = width;
836 logfont.lfEscapement = esc;
837 logfont.lfOrientation = orient;
838 logfont.lfWeight = weight;
839 logfont.lfItalic = italic;
840 logfont.lfUnderline = underline;
841 logfont.lfStrikeOut = strikeout;
842 logfont.lfCharSet = charset;
843 logfont.lfOutPrecision = outpres;
844 logfont.lfClipPrecision = clippres;
845 logfont.lfQuality = quality;
846 logfont.lfPitchAndFamily = pitch;
848 if (name)
849 lstrcpynA( logfont.lfFaceName, name, sizeof(logfont.lfFaceName) );
850 else
851 logfont.lfFaceName[0] = '\0';
853 return CreateFontIndirectA( &logfont );
856 /*************************************************************************
857 * CreateFontW (GDI32.@)
859 HFONT WINAPI CreateFontW( INT height, INT width, INT esc, INT orient, INT weight,
860 DWORD italic, DWORD underline, DWORD strikeout,
861 DWORD charset, DWORD outpres, DWORD clippres,
862 DWORD quality, DWORD pitch, const WCHAR *name )
864 LOGFONTW logfont;
866 logfont.lfHeight = height;
867 logfont.lfWidth = width;
868 logfont.lfEscapement = esc;
869 logfont.lfOrientation = orient;
870 logfont.lfWeight = weight;
871 logfont.lfItalic = italic;
872 logfont.lfUnderline = underline;
873 logfont.lfStrikeOut = strikeout;
874 logfont.lfCharSet = charset;
875 logfont.lfOutPrecision = outpres;
876 logfont.lfClipPrecision = clippres;
877 logfont.lfQuality = quality;
878 logfont.lfPitchAndFamily = pitch;
880 if (name)
881 lstrcpynW( logfont.lfFaceName, name, ARRAY_SIZE(logfont.lfFaceName) );
882 else
883 logfont.lfFaceName[0] = '\0';
885 return CreateFontIndirectW( &logfont );
888 /***********************************************************************
889 * ExtTextOutW (GDI32.@)
891 BOOL WINAPI ExtTextOutW( HDC hdc, INT x, INT y, UINT flags, const RECT *rect,
892 const WCHAR *str, UINT count, const INT *dx )
894 WORD *glyphs = NULL;
895 DC_ATTR *dc_attr;
896 BOOL ret;
898 if (count > INT_MAX) return FALSE;
899 if (is_meta_dc( hdc )) return METADC_ExtTextOut( hdc, x, y, flags, rect, str, count, dx );
900 if (!(dc_attr = get_dc_attr( hdc ))) return FALSE;
901 if (dc_attr->emf && !EMFDC_ExtTextOut( dc_attr, x, y, flags, rect, str, count, dx ))
902 return FALSE;
904 if (!(flags & (ETO_GLYPH_INDEX | ETO_IGNORELANGUAGE)) && count > 0)
906 UINT bidi_flags;
907 int glyphs_count;
909 bidi_flags = (dc_attr->text_align & TA_RTLREADING) || (flags & ETO_RTLREADING)
910 ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR;
912 BIDI_Reorder( hdc, str, count, GCP_REORDER, bidi_flags, NULL, 0, NULL,
913 &glyphs, &glyphs_count );
915 flags |= ETO_IGNORELANGUAGE;
916 if (glyphs)
918 flags |= ETO_GLYPH_INDEX;
919 count = glyphs_count;
920 str = glyphs;
924 ret = NtGdiExtTextOutW( hdc, x, y, flags, rect, str, count, dx, 0 );
926 HeapFree( GetProcessHeap(), 0, glyphs );
927 return ret;
930 /***********************************************************************
931 * ExtTextOutA (GDI32.@)
933 BOOL WINAPI ExtTextOutA( HDC hdc, INT x, INT y, UINT flags, const RECT *rect,
934 const char *str, UINT count, const INT *dx )
936 INT wlen;
937 UINT codepage;
938 WCHAR *p;
939 BOOL ret;
940 INT *dxW = NULL;
942 if (count > INT_MAX) return FALSE;
944 if (flags & ETO_GLYPH_INDEX)
945 return ExtTextOutW( hdc, x, y, flags, rect, (const WCHAR *)str, count, dx );
947 p = text_mbtowc( hdc, str, count, &wlen, &codepage );
949 if (dx)
951 unsigned int i = 0, j = 0;
953 /* allocate enough for a ETO_PDY */
954 dxW = HeapAlloc( GetProcessHeap(), 0, 2 * wlen * sizeof(INT) );
955 while (i < count)
957 if (IsDBCSLeadByteEx( codepage, str[i] ))
959 if (flags & ETO_PDY)
961 dxW[j++] = dx[i * 2] + dx[(i + 1) * 2];
962 dxW[j++] = dx[i * 2 + 1] + dx[(i + 1) * 2 + 1];
964 else
965 dxW[j++] = dx[i] + dx[i + 1];
966 i = i + 2;
968 else
970 if (flags & ETO_PDY)
972 dxW[j++] = dx[i * 2];
973 dxW[j++] = dx[i * 2 + 1];
975 else
976 dxW[j++] = dx[i];
977 i = i + 1;
982 ret = ExtTextOutW( hdc, x, y, flags, rect, p, wlen, dxW );
984 HeapFree( GetProcessHeap(), 0, p );
985 HeapFree( GetProcessHeap(), 0, dxW );
986 return ret;
989 /***********************************************************************
990 * TextOutA (GDI32.@)
992 BOOL WINAPI TextOutA( HDC hdc, INT x, INT y, const char *str, INT count )
994 return ExtTextOutA( hdc, x, y, 0, NULL, str, count, NULL );
997 /***********************************************************************
998 * TextOutW (GDI32.@)
1000 BOOL WINAPI TextOutW( HDC hdc, INT x, INT y, const WCHAR *str, INT count )
1002 return ExtTextOutW( hdc, x, y, 0, NULL, str, count, NULL );
1006 /***********************************************************************
1007 * PolyTextOutA (GDI32.@)
1009 BOOL WINAPI PolyTextOutA( HDC hdc, const POLYTEXTA *pt, INT count )
1011 for (; count>0; count--, pt++)
1012 if (!ExtTextOutA( hdc, pt->x, pt->y, pt->uiFlags, &pt->rcl, pt->lpstr, pt->n, pt->pdx ))
1013 return FALSE;
1014 return TRUE;
1017 /***********************************************************************
1018 * PolyTextOutW (GDI32.@)
1020 BOOL WINAPI PolyTextOutW( HDC hdc, const POLYTEXTW *pt, INT count )
1022 for (; count>0; count--, pt++)
1023 if (!ExtTextOutW( hdc, pt->x, pt->y, pt->uiFlags, &pt->rcl, pt->lpstr, pt->n, pt->pdx ))
1024 return FALSE;
1025 return TRUE;
1028 static int kern_pair( const KERNINGPAIR *kern, int count, WCHAR c1, WCHAR c2 )
1030 int i;
1032 for (i = 0; i < count; i++)
1034 if (kern[i].wFirst == c1 && kern[i].wSecond == c2)
1035 return kern[i].iKernAmount;
1038 return 0;
1041 static int *kern_string( HDC hdc, const WCHAR *str, int len, int *kern_total )
1043 unsigned int i, count;
1044 KERNINGPAIR *kern = NULL;
1045 int *ret;
1047 *kern_total = 0;
1049 ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(*ret) );
1050 if (!ret) return NULL;
1052 count = GetKerningPairsW( hdc, 0, NULL );
1053 if (count)
1055 kern = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*kern) );
1056 if (!kern)
1058 HeapFree( GetProcessHeap(), 0, ret );
1059 return NULL;
1062 GetKerningPairsW( hdc, count, kern );
1065 for (i = 0; i < len - 1; i++)
1067 ret[i] = kern_pair( kern, count, str[i], str[i + 1] );
1068 *kern_total += ret[i];
1071 ret[len - 1] = 0; /* no kerning for last element */
1073 HeapFree( GetProcessHeap(), 0, kern );
1074 return ret;
1077 /*************************************************************************
1078 * GetCharacterPlacementW (GDI32.@)
1080 * Retrieve information about a string. This includes the width, reordering,
1081 * Glyphing and so on.
1083 * RETURNS
1085 * The width and height of the string if successful, 0 if failed.
1087 * BUGS
1089 * All flags except GCP_REORDER are not yet implemented.
1090 * Reordering is not 100% compliant to the Windows BiDi method.
1091 * Caret positioning is not yet implemented for BiDi.
1092 * Classes are not yet implemented.
1095 DWORD WINAPI GetCharacterPlacementW( HDC hdc, const WCHAR *str, INT count, INT max_extent,
1096 GCP_RESULTSW *result, DWORD flags )
1098 int *kern = NULL, kern_total = 0;
1099 UINT i, set_cnt;
1100 SIZE size;
1101 DWORD ret = 0;
1103 TRACE("%s, %d, %d, 0x%08x\n", debugstr_wn(str, count), count, max_extent, flags);
1105 if (!count)
1106 return 0;
1108 if (!result)
1109 return GetTextExtentPoint32W( hdc, str, count, &size ) ? MAKELONG(size.cx, size.cy) : 0;
1111 TRACE( "lStructSize=%d, lpOutString=%p, lpOrder=%p, lpDx=%p, lpCaretPos=%p\n"
1112 "lpClass=%p, lpGlyphs=%p, nGlyphs=%u, nMaxFit=%d\n",
1113 result->lStructSize, result->lpOutString, result->lpOrder,
1114 result->lpDx, result->lpCaretPos, result->lpClass,
1115 result->lpGlyphs, result->nGlyphs, result->nMaxFit );
1117 if (flags & ~(GCP_REORDER | GCP_USEKERNING))
1118 FIXME( "flags 0x%08x ignored\n", flags );
1119 if (result->lpClass)
1120 FIXME( "classes not implemented\n" );
1121 if (result->lpCaretPos && (flags & GCP_REORDER))
1122 FIXME( "Caret positions for complex scripts not implemented\n" );
1124 set_cnt = (UINT)count;
1125 if (set_cnt > result->nGlyphs) set_cnt = result->nGlyphs;
1127 /* return number of initialized fields */
1128 result->nGlyphs = set_cnt;
1130 if (!(flags & GCP_REORDER))
1132 /* Treat the case where no special handling was requested in a fastpath way */
1133 /* copy will do if the GCP_REORDER flag is not set */
1134 if (result->lpOutString)
1135 memcpy( result->lpOutString, str, set_cnt * sizeof(WCHAR) );
1137 if (result->lpOrder)
1139 for (i = 0; i < set_cnt; i++)
1140 result->lpOrder[i] = i;
1143 else
1145 BIDI_Reorder( NULL, str, count, flags, WINE_GCPW_FORCE_LTR, result->lpOutString,
1146 set_cnt, result->lpOrder, NULL, NULL );
1149 if (flags & GCP_USEKERNING)
1151 kern = kern_string( hdc, str, set_cnt, &kern_total );
1152 if (!kern)
1154 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1155 return 0;
1159 /* FIXME: Will use the placement chars */
1160 if (result->lpDx)
1162 int c;
1163 for (i = 0; i < set_cnt; i++)
1165 if (GetCharWidth32W( hdc, str[i], str[i], &c ))
1167 result->lpDx[i] = c;
1168 if (flags & GCP_USEKERNING)
1169 result->lpDx[i] += kern[i];
1174 if (result->lpCaretPos && !(flags & GCP_REORDER))
1176 unsigned int pos = 0;
1178 result->lpCaretPos[0] = 0;
1179 for (i = 0; i < set_cnt - 1; i++)
1181 if (flags & GCP_USEKERNING)
1182 pos += kern[i];
1184 if (GetTextExtentPoint32W( hdc, &str[i], 1, &size ))
1185 result->lpCaretPos[i + 1] = (pos += size.cx);
1189 if (result->lpGlyphs)
1190 GetGlyphIndicesW( hdc, str, set_cnt, result->lpGlyphs, 0 );
1192 if (GetTextExtentPoint32W( hdc, str, count, &size ))
1193 ret = MAKELONG( size.cx + kern_total, size.cy );
1195 HeapFree( GetProcessHeap(), 0, kern );
1196 return ret;
1199 /*************************************************************************
1200 * GetCharacterPlacementA (GDI32.@)
1202 DWORD WINAPI GetCharacterPlacementA( HDC hdc, const char *str, INT count, INT max_extent,
1203 GCP_RESULTSA *result, DWORD flags )
1205 GCP_RESULTSW resultsW;
1206 WCHAR *strW;
1207 INT countW;
1208 DWORD ret;
1209 UINT font_cp;
1211 TRACE( "%s, %d, %d, 0x%08x\n", debugstr_an(str, count), count, max_extent, flags );
1213 strW = text_mbtowc( hdc, str, count, &countW, &font_cp );
1215 if (!result)
1217 ret = GetCharacterPlacementW( hdc, strW, countW, max_extent, NULL, flags );
1218 HeapFree( GetProcessHeap(), 0, strW );
1219 return ret;
1222 /* both structs are equal in size */
1223 memcpy( &resultsW, result, sizeof(resultsW) );
1225 if (result->lpOutString)
1226 resultsW.lpOutString = HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR) * countW );
1228 ret = GetCharacterPlacementW( hdc, strW, countW, max_extent, &resultsW, flags );
1230 result->nGlyphs = resultsW.nGlyphs;
1231 result->nMaxFit = resultsW.nMaxFit;
1233 if (result->lpOutString)
1234 WideCharToMultiByte( font_cp, 0, resultsW.lpOutString, countW,
1235 result->lpOutString, count, NULL, NULL );
1237 HeapFree( GetProcessHeap(), 0, strW );
1238 HeapFree( GetProcessHeap(), 0, resultsW.lpOutString );
1239 return ret;
1242 /***********************************************************************
1243 * GetTextFaceA (GDI32.@)
1245 INT WINAPI GetTextFaceA( HDC hdc, INT count, char *name )
1247 INT res = GetTextFaceW( hdc, 0, NULL );
1248 WCHAR *nameW = HeapAlloc( GetProcessHeap(), 0, res * sizeof(WCHAR) );
1250 GetTextFaceW( hdc, res, nameW );
1251 if (name)
1253 if (count)
1255 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, name, count, NULL, NULL );
1256 if (res == 0) res = count;
1257 name[count - 1] = 0;
1258 /* GetTextFaceA does NOT include the nul byte in the return count. */
1259 res--;
1261 else
1262 res = 0;
1264 else
1265 res = WideCharToMultiByte( CP_ACP, 0, nameW, -1, NULL, 0, NULL, NULL );
1266 HeapFree( GetProcessHeap(), 0, nameW );
1267 return res;
1270 /***********************************************************************
1271 * GetTextFaceW (GDI32.@)
1273 INT WINAPI GetTextFaceW( HDC hdc, INT count, WCHAR *name )
1275 return NtGdiGetTextFaceW( hdc, count, name, FALSE );
1278 /***********************************************************************
1279 * GetTextExtentExPointW (GDI32.@)
1281 BOOL WINAPI GetTextExtentExPointW( HDC hdc, const WCHAR *str, INT count, INT max_ext,
1282 INT *nfit, INT *dxs, SIZE *size )
1284 return NtGdiGetTextExtentExW( hdc, str, count, max_ext, nfit, dxs, size, 0 );
1287 /***********************************************************************
1288 * GetTextExtentExPointI (GDI32.@)
1290 BOOL WINAPI GetTextExtentExPointI( HDC hdc, const WORD *indices, INT count, INT max_ext,
1291 INT *nfit, INT *dxs, SIZE *size )
1293 return NtGdiGetTextExtentExW( hdc, indices, count, max_ext, nfit, dxs, size, 1 );
1296 /***********************************************************************
1297 * GetTextExtentExPointA (GDI32.@)
1299 BOOL WINAPI GetTextExtentExPointA( HDC hdc, const char *str, INT count, INT max_ext,
1300 INT *nfit, INT *dxs, SIZE *size )
1302 BOOL ret;
1303 INT wlen;
1304 INT *wdxs = NULL;
1305 WCHAR *p = NULL;
1307 if (count < 0 || max_ext < -1) return FALSE;
1309 if (dxs)
1311 wdxs = HeapAlloc( GetProcessHeap(), 0, count * sizeof(INT) );
1312 if (!wdxs) return FALSE;
1315 p = text_mbtowc( hdc, str, count, &wlen, NULL );
1316 ret = GetTextExtentExPointW( hdc, p, wlen, max_ext, nfit, wdxs, size );
1317 if (wdxs)
1319 INT n = nfit ? *nfit : wlen;
1320 INT i, j;
1321 for (i = 0, j = 0; i < n; i++, j++)
1323 dxs[j] = wdxs[i];
1324 if (IsDBCSLeadByte( str[j] )) dxs[++j] = wdxs[i];
1327 if (nfit) *nfit = WideCharToMultiByte( CP_ACP, 0, p, *nfit, NULL, 0, NULL, NULL );
1328 HeapFree( GetProcessHeap(), 0, p );
1329 HeapFree( GetProcessHeap(), 0, wdxs );
1330 return ret;
1333 /***********************************************************************
1334 * GetTextExtentPoint32W (GDI32.@)
1336 BOOL WINAPI GetTextExtentPoint32W( HDC hdc, const WCHAR *str, INT count, SIZE *size )
1338 return GetTextExtentExPointW( hdc, str, count, 0, NULL, NULL, size );
1341 /***********************************************************************
1342 * GetTextExtentPoint32A (GDI32.@)
1344 BOOL WINAPI GetTextExtentPoint32A( HDC hdc, const char *str, INT count, SIZE *size )
1346 return GetTextExtentExPointA( hdc, str, count, 0, NULL, NULL, size );
1349 /***********************************************************************
1350 * GetTextExtentPointI (GDI32.@)
1352 BOOL WINAPI GetTextExtentPointI( HDC hdc, const WORD *indices, INT count, SIZE *size )
1354 return GetTextExtentExPointI( hdc, indices, count, 0, NULL, NULL, size );
1357 /***********************************************************************
1358 * GetTextExtentPointA (GDI32.@)
1360 BOOL WINAPI GetTextExtentPointA( HDC hdc, const char *str, INT count, SIZE *size )
1362 return GetTextExtentPoint32A( hdc, str, count, size );
1365 /***********************************************************************
1366 * GetTextExtentPointW (GDI32.@)
1368 BOOL WINAPI GetTextExtentPointW( HDC hdc, const WCHAR *str, INT count, SIZE *size )
1370 return GetTextExtentPoint32W( hdc, str, count, size );
1373 /***********************************************************************
1374 * GetTextMetricsW (GDI32.@)
1376 BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
1378 return NtGdiGetTextMetricsW( hdc, metrics, 0 );
1381 /***********************************************************************
1382 * GetTextMetricsA (GDI32.@)
1384 BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
1386 TEXTMETRICW tm32;
1388 if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
1389 text_metric_WtoA( &tm32, metrics );
1390 return TRUE;
1393 /***********************************************************************
1394 * GetOutlineTextMetricsA (GDI32.@)
1396 * Gets metrics for TrueType fonts.
1398 * NOTES
1399 * If the supplied buffer isn't big enough Windows partially fills it up to
1400 * its given length and returns that length.
1402 UINT WINAPI GetOutlineTextMetricsA( HDC hdc, UINT size, OUTLINETEXTMETRICA *otm )
1404 char buf[512], *ptr;
1405 UINT ret, needed;
1406 OUTLINETEXTMETRICW *otmW = (OUTLINETEXTMETRICW *)buf;
1407 OUTLINETEXTMETRICA *output = otm;
1408 INT left, len;
1410 if ((ret = GetOutlineTextMetricsW( hdc, 0, NULL )) == 0) return 0;
1411 if (ret > sizeof(buf) && !(otmW = HeapAlloc( GetProcessHeap(), 0, ret )))
1412 return 0;
1414 GetOutlineTextMetricsW( hdc, ret, otmW );
1416 needed = sizeof(OUTLINETEXTMETRICA);
1417 if (otmW->otmpFamilyName)
1418 needed += WideCharToMultiByte( CP_ACP, 0,
1419 (WCHAR *)((char *)otmW + (ptrdiff_t)otmW->otmpFamilyName),
1420 -1, NULL, 0, NULL, NULL );
1421 if (otmW->otmpFaceName)
1422 needed += WideCharToMultiByte( CP_ACP, 0,
1423 (WCHAR *)((char *)otmW + (ptrdiff_t)otmW->otmpFaceName),
1424 -1, NULL, 0, NULL, NULL );
1425 if (otmW->otmpStyleName)
1426 needed += WideCharToMultiByte( CP_ACP, 0,
1427 (WCHAR *)((char *)otmW + (ptrdiff_t)otmW->otmpStyleName),
1428 -1, NULL, 0, NULL, NULL );
1429 if (otmW->otmpFullName)
1430 needed += WideCharToMultiByte( CP_ACP, 0,
1431 (WCHAR *)((char *)otmW + (ptrdiff_t)otmW->otmpFullName),
1432 -1, NULL, 0, NULL, NULL );
1434 if (!otm)
1436 ret = needed;
1437 goto end;
1440 TRACE( "needed = %d\n", needed );
1441 if (needed > size)
1442 /* Since the supplied buffer isn't big enough, we'll alloc one
1443 that is and memcpy the first size bytes into the otm at
1444 the end. */
1445 output = HeapAlloc( GetProcessHeap(), 0, needed );
1447 ret = output->otmSize = min( needed, size );
1448 text_metric_WtoA( &otmW->otmTextMetrics, &output->otmTextMetrics );
1449 output->otmFiller = 0;
1450 output->otmPanoseNumber = otmW->otmPanoseNumber;
1451 output->otmfsSelection = otmW->otmfsSelection;
1452 output->otmfsType = otmW->otmfsType;
1453 output->otmsCharSlopeRise = otmW->otmsCharSlopeRise;
1454 output->otmsCharSlopeRun = otmW->otmsCharSlopeRun;
1455 output->otmItalicAngle = otmW->otmItalicAngle;
1456 output->otmEMSquare = otmW->otmEMSquare;
1457 output->otmAscent = otmW->otmAscent;
1458 output->otmDescent = otmW->otmDescent;
1459 output->otmLineGap = otmW->otmLineGap;
1460 output->otmsCapEmHeight = otmW->otmsCapEmHeight;
1461 output->otmsXHeight = otmW->otmsXHeight;
1462 output->otmrcFontBox = otmW->otmrcFontBox;
1463 output->otmMacAscent = otmW->otmMacAscent;
1464 output->otmMacDescent = otmW->otmMacDescent;
1465 output->otmMacLineGap = otmW->otmMacLineGap;
1466 output->otmusMinimumPPEM = otmW->otmusMinimumPPEM;
1467 output->otmptSubscriptSize = otmW->otmptSubscriptSize;
1468 output->otmptSubscriptOffset = otmW->otmptSubscriptOffset;
1469 output->otmptSuperscriptSize = otmW->otmptSuperscriptSize;
1470 output->otmptSuperscriptOffset = otmW->otmptSuperscriptOffset;
1471 output->otmsStrikeoutSize = otmW->otmsStrikeoutSize;
1472 output->otmsStrikeoutPosition = otmW->otmsStrikeoutPosition;
1473 output->otmsUnderscoreSize = otmW->otmsUnderscoreSize;
1474 output->otmsUnderscorePosition = otmW->otmsUnderscorePosition;
1476 ptr = (char *)(output + 1);
1477 left = needed - sizeof(*output);
1479 if (otmW->otmpFamilyName)
1481 output->otmpFamilyName = (char *)(ptr - (char *)output);
1482 len = WideCharToMultiByte( CP_ACP, 0,
1483 (WCHAR *)((char *)otmW + (ptrdiff_t)otmW->otmpFamilyName),
1484 -1, ptr, left, NULL, NULL );
1485 left -= len;
1486 ptr += len;
1488 else output->otmpFamilyName = 0;
1490 if (otmW->otmpFaceName)
1492 output->otmpFaceName = (char *)(ptr - (char *)output);
1493 len = WideCharToMultiByte( CP_ACP, 0,
1494 (WCHAR *)((char *)otmW + (ptrdiff_t)otmW->otmpFaceName),
1495 -1, ptr, left, NULL, NULL );
1496 left -= len;
1497 ptr += len;
1499 else output->otmpFaceName = 0;
1501 if (otmW->otmpStyleName)
1503 output->otmpStyleName = (char *)(ptr - (char *)output);
1504 len = WideCharToMultiByte( CP_ACP, 0,
1505 (WCHAR *)((char *)otmW + (ptrdiff_t)otmW->otmpStyleName),
1506 -1, ptr, left, NULL, NULL);
1507 left -= len;
1508 ptr += len;
1510 else output->otmpStyleName = 0;
1512 if (otmW->otmpFullName)
1514 output->otmpFullName = (char *)(ptr - (char *)output);
1515 len = WideCharToMultiByte( CP_ACP, 0,
1516 (WCHAR *)((char *)otmW + (ptrdiff_t)otmW->otmpFullName),
1517 -1, ptr, left, NULL, NULL );
1518 left -= len;
1520 else output->otmpFullName = 0;
1522 assert( left == 0 );
1524 if (output != otm)
1526 memcpy( otm, output, size );
1527 HeapFree( GetProcessHeap(), 0, output );
1529 /* check if the string offsets really fit into the provided size */
1530 /* FIXME: should we check string length as well? */
1531 /* make sure that we don't read/write beyond the provided buffer */
1532 if (otm->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFamilyName) + sizeof(char *))
1534 if ((UINT_PTR)otm->otmpFamilyName >= otm->otmSize)
1535 otm->otmpFamilyName = 0; /* doesn't fit */
1538 /* make sure that we don't read/write beyond the provided buffer */
1539 if (otm->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFaceName) + sizeof(char *))
1541 if ((UINT_PTR)otm->otmpFaceName >= otm->otmSize)
1542 otm->otmpFaceName = 0; /* doesn't fit */
1545 /* make sure that we don't read/write beyond the provided buffer */
1546 if (otm->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpStyleName) + sizeof(char *))
1548 if ((UINT_PTR)otm->otmpStyleName >= otm->otmSize)
1549 otm->otmpStyleName = 0; /* doesn't fit */
1552 /* make sure that we don't read/write beyond the provided buffer */
1553 if (otm->otmSize >= FIELD_OFFSET(OUTLINETEXTMETRICA, otmpFullName) + sizeof(char *))
1555 if ((UINT_PTR)otm->otmpFullName >= otm->otmSize)
1556 otm->otmpFullName = 0; /* doesn't fit */
1560 end:
1561 if (otmW != (OUTLINETEXTMETRICW *)buf)
1562 HeapFree(GetProcessHeap(), 0, otmW);
1563 return ret;
1566 /***********************************************************************
1567 * GetOutlineTextMetricsW [GDI32.@]
1569 UINT WINAPI GetOutlineTextMetricsW( HDC hdc, UINT size, OUTLINETEXTMETRICW *otm )
1571 return NtGdiGetOutlineTextMetricsInternalW( hdc, size, otm, 0 );
1574 /***********************************************************************
1575 * GetCharWidthW (GDI32.@)
1576 * GetCharWidth32W (GDI32.@)
1578 BOOL WINAPI GetCharWidth32W( HDC hdc, UINT first, UINT last, INT *buffer )
1580 return NtGdiGetCharWidthW( hdc, first, last, NULL, NTGDI_GETCHARWIDTH_INT, buffer );
1583 static WCHAR *get_chars_by_range( HDC hdc, UINT first, UINT last, INT *ret_len )
1585 INT i, count = last - first + 1;
1586 WCHAR *wstr;
1587 char *str;
1588 UINT mbcp;
1589 UINT c;
1591 if (count <= 0)
1592 return NULL;
1594 mbcp = GdiGetCodePage( hdc );
1595 switch (mbcp)
1597 case 932:
1598 case 936:
1599 case 949:
1600 case 950:
1601 case 1361:
1602 if (last > 0xffff)
1603 return NULL;
1604 if ((first ^ last) > 0xff)
1605 return NULL;
1606 break;
1607 default:
1608 if (last > 0xff)
1609 return NULL;
1610 mbcp = 0;
1611 break;
1614 if (!(str = HeapAlloc( GetProcessHeap(), 0, count * 2 + 1 )))
1615 return NULL;
1617 for (i = 0, c = first; c <= last; i++, c++)
1619 if (mbcp) {
1620 if (c > 0xff)
1621 str[i++] = (BYTE)(c >> 8);
1622 if (c <= 0xff && IsDBCSLeadByteEx( mbcp, c ))
1623 str[i] = 0x1f; /* FIXME: use default character */
1624 else
1625 str[i] = (BYTE)c;
1627 else
1628 str[i] = (BYTE)c;
1630 str[i] = '\0';
1632 wstr = text_mbtowc( hdc, str, i, ret_len, NULL );
1633 HeapFree( GetProcessHeap(), 0, str );
1634 return wstr;
1637 /***********************************************************************
1638 * GetCharWidthA (GDI32.@)
1639 * GetCharWidth32A (GDI32.@)
1641 BOOL WINAPI GetCharWidth32A( HDC hdc, UINT first, UINT last, INT *buffer )
1643 WCHAR *chars;
1644 INT count;
1645 BOOL ret;
1647 if (!(chars = get_chars_by_range( hdc, first, last, &count ))) return FALSE;
1648 ret = NtGdiGetCharWidthW( hdc, 0, count, chars, NTGDI_GETCHARWIDTH_INT, buffer );
1649 HeapFree( GetProcessHeap(), 0, chars );
1650 return ret;
1653 /***********************************************************************
1654 * GetCharWidthFloatW (GDI32.@)
1656 BOOL WINAPI GetCharWidthFloatW( HDC hdc, UINT first, UINT last, float *buffer )
1658 return NtGdiGetCharWidthW( hdc, first, last, NULL, 0, buffer );
1661 /***********************************************************************
1662 * GetCharWidthFloatA (GDI32.@)
1664 BOOL WINAPI GetCharWidthFloatA( HDC hdc, UINT first, UINT last, float *buffer )
1666 WCHAR *chars;
1667 INT count;
1668 BOOL ret;
1670 if (!(chars = get_chars_by_range( hdc, first, last, &count ))) return FALSE;
1671 ret = NtGdiGetCharWidthW( hdc, 0, count, chars, 0, buffer );
1672 HeapFree( GetProcessHeap(), 0, chars );
1673 return ret;
1676 /***********************************************************************
1677 * GetCharWidthI (GDI32.@)
1679 BOOL WINAPI GetCharWidthI( HDC hdc, UINT first, UINT count, WORD *glyphs, INT *buffer )
1681 TRACE( "(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer );
1682 return NtGdiGetCharWidthW( hdc, first, count, glyphs,
1683 NTGDI_GETCHARWIDTH_INT | NTGDI_GETCHARWIDTH_INDICES, buffer );
1686 /***********************************************************************
1687 * GetCharABCWidthsW (GDI32.@)
1689 BOOL WINAPI GetCharABCWidthsW( HDC hdc, UINT first, UINT last, ABC *abc )
1691 return NtGdiGetCharABCWidthsW( hdc, first, last, NULL, NTGDI_GETCHARABCWIDTHS_INT, abc );
1694 /***********************************************************************
1695 * GetCharABCWidthsA (GDI32.@)
1697 * See GetCharABCWidthsW.
1699 BOOL WINAPI GetCharABCWidthsA( HDC hdc, UINT first, UINT last, ABC *abc )
1701 WCHAR *chars;
1702 INT count;
1703 BOOL ret;
1705 if (!(chars = get_chars_by_range( hdc, first, last, &count ))) return FALSE;
1706 ret = NtGdiGetCharABCWidthsW( hdc, 0, count, chars, NTGDI_GETCHARABCWIDTHS_INT, abc );
1707 HeapFree( GetProcessHeap(), 0, chars );
1708 return ret;
1711 /***********************************************************************
1712 * GetCharABCWidthsI (GDI32.@)
1714 BOOL WINAPI GetCharABCWidthsI( HDC hdc, UINT first, UINT count, WORD *glyphs, ABC *buffer )
1716 TRACE( "(%p, %d, %d, %p, %p)\n", hdc, first, count, glyphs, buffer );
1717 return NtGdiGetCharABCWidthsW( hdc, first, count, glyphs,
1718 NTGDI_GETCHARABCWIDTHS_INDICES | NTGDI_GETCHARABCWIDTHS_INT,
1719 buffer );