source: trunk/src/gdi32/text.cpp@ 10163

Last change on this file since 10163 was 10163, checked in by sandervl, 22 years ago

KOM: Fixed InternalTextOutW() and GetTextExtentPointW() to support unicode correctly. (DBCS)

File size: 16.6 KB
Line 
1/* $Id: text.cpp,v 1.34 2003-07-14 13:43:15 sandervl Exp $ */
2
3/*
4 * GDI32 text apis
5 *
6 * Based on Wine code (991031) (objects\text.c)
7 *
8 * Copyright 1993, 1994 Alexandre Julliard
9 * Copyright 1999-2000 Christoph Bratschi
10 *
11 * Project Odin Software License can be found in LICENSE.TXT
12 *
13 */
14#include <os2win.h>
15#include <stdlib.h>
16#include <stdio.h>
17#include <misc.h>
18#include <string.h>
19#include <float.h>
20#include "oslibgpi.h"
21#include <dcdata.h>
22#include <unicode.h>
23
24#define DBG_LOCALLOG DBG_text
25#include "dbglocal.h"
26
27#define ELLIPSIS "..."
28#define ELLIPSISLEN 3
29
30//******************************************************************************
31//******************************************************************************
32UINT WINAPI GetTextCharsetInfo(
33 HDC hdc, /* [in] Handle to device context */
34 LPFONTSIGNATURE fs, /* [out] Pointer to struct to receive data */
35 DWORD flags) /* [in] Reserved - must be 0 */
36{
37 HGDIOBJ hFont;
38 UINT charSet = DEFAULT_CHARSET;
39 LOGFONTW lf;
40 CHARSETINFO csinfo;
41
42 dprintf(("GetTextCharsetInfo %x %x %x", hdc, fs, flags));
43
44 hFont = GetCurrentObject(hdc, OBJ_FONT);
45 if (hFont == 0)
46 return(DEFAULT_CHARSET);
47 if ( GetObjectW(hFont, sizeof(LOGFONTW), &lf) != 0 )
48 charSet = lf.lfCharSet;
49
50 if (fs != NULL) {
51 if (!TranslateCharsetInfo((LPDWORD)charSet, &csinfo, TCI_SRCCHARSET))
52 return (DEFAULT_CHARSET);
53 memcpy(fs, &csinfo.fs, sizeof(FONTSIGNATURE));
54 }
55 return charSet;
56}
57/***********************************************************************
58 * GetTextCharset32 [GDI32.226] Gets character set for font in DC
59 *
60 * NOTES
61 * Should it return a UINT32 instead of an INT32?
62 * => YES, as GetTextCharsetInfo returns UINT32
63 *
64 * RETURNS
65 * Success: Character set identifier
66 * Failure: DEFAULT_CHARSET
67 */
68UINT WINAPI GetTextCharset(HDC hdc) /* [in] Handle to device context */
69{
70 /* MSDN docs say this is equivalent */
71 return GetTextCharsetInfo(hdc, NULL, 0);
72}
73//******************************************************************************
74// todo: metafile support
75//#undef INVERT
76//#define INVERT_SETYINVERSION
77//******************************************************************************
78BOOL InternalTextOutA(HDC hdc,int X,int Y,UINT fuOptions,CONST RECT *lprc,LPCSTR lpszString,INT cbCount,CONST INT *lpDx,BOOL IsExtTextOut)
79{
80 pDCData pHps = (pDCData)OSLibGpiQueryDCData(hdc);
81 ULONG flOptions = 0;
82 RECTLOS2 pmRect;
83 POINTLOS2 ptl;
84 LONG hits;
85
86 if (!pHps || (cbCount < 0) || ((lpszString == NULL) && (cbCount != 0)))
87 {
88 dprintf(("InternalTextOutA: invalid parameter"));
89 SetLastError(ERROR_INVALID_HANDLE);
90 return FALSE;
91 }
92
93 if (cbCount > 512)
94 {
95 dprintf(("InternalTextOutA: invalid parameter cbCount"));
96 SetLastError(ERROR_INVALID_PARAMETER);
97 return FALSE;
98 }
99 if (fuOptions & ~((UINT)(ETO_CLIPPED | ETO_OPAQUE)))
100 {
101 dprintf(("InternalTextOutA: invalid fuOptions"));
102 //ETO_GLYPH_INDEX, ETO_RTLLEADING, ETO_NUMERICSLOCAL, ETO_NUMERICSLATIN, ETO_IGNORELANGUAGE, ETO_PDY are ignored
103 return TRUE;
104 }
105
106#if defined(INVERT) && !defined(INVERT_SETYINVERSION)
107 if(pHps->yInvert > 0) {
108 Y = pHps->yInvert - Y;
109 }
110#endif
111
112#ifdef INVERT_SETYINVERSION
113 int oldyinv = GpiQueryYInversion(pHps->hps);
114 Y = oldyinv - Y;
115#endif
116
117 //CB: add metafile info
118
119 if (lprc)
120 {
121 if (fuOptions)
122 {
123 MapWin32ToOS2Rect(*lprc,pmRect);
124 if (excludeBottomRightPoint(pHps,(PPOINTLOS2)&pmRect) == 0)
125 {
126 dprintf(("InternalTextOutA: excludeBottomRightPoint returned 0"));
127 return TRUE;
128 }
129#ifndef INVERT
130#ifdef INVERT_SETYINVERSION
131 if (oldyinv) {
132 int temp = oldyinv - pmRect.yTop;
133 pmRect.yTop = oldyinv - pmRect.yBottom;
134 pmRect.yBottom = temp;
135 }
136#else
137 if (pHps->yInvert > 0) {
138 int temp = pHps->yInvert - pmRect.yTop;
139 pmRect.yTop = pHps->yInvert - pmRect.yBottom;
140 pmRect.yBottom = temp;
141 }
142#endif
143#endif
144
145 if (fuOptions & ETO_CLIPPED) flOptions |= CHSOS_CLIP;
146 if (fuOptions & ETO_OPAQUE) flOptions |= CHSOS_OPAQUE;
147 }
148 }
149 else
150 {
151 if (fuOptions)
152 {
153 dprintf(("InternalTextOutA: ERROR_INVALID_HANDLE"));
154 SetLastError(ERROR_INVALID_HANDLE);
155 return FALSE;
156 }
157 }
158
159 if (cbCount == 0)
160 {
161 if (fuOptions & ETO_OPAQUE)
162 {
163//SvL: This doesn't seem to work (anymore). Look at MFC apps for the missing border
164// between menu & button bar (all white). (e.g. odin app & acrobat reader 4.05)
165#if 0
166 lpszString = " ";
167 cbCount = 1;
168 flOptions |= CHSOS_CLIP;
169#else
170 HBRUSH hbrush = CreateSolidBrush(GetBkColor(hdc));
171 HBRUSH oldbrush;
172
173 oldbrush = SelectObject(hdc, hbrush);
174 FillRect(hdc, lprc, hbrush);
175 SelectObject(hdc, oldbrush);
176 DeleteObject(hbrush);
177 return TRUE;
178#endif
179 }
180 else {
181 dprintf(("InternalTextOutA: cbCount == 0"));
182 return TRUE;
183 }
184 }
185
186#ifdef INVERT_SETYINVERSION
187 GpiEnableYInversion(pHps->hps, 0);
188#endif
189
190 if (lpDx)
191 flOptions |= CHSOS_VECTOR;
192
193 if (!getAlignUpdateCP(pHps))
194 {
195 ptl.x = X;
196 ptl.y = Y;
197
198 flOptions |= CHSOS_LEAVEPOS;
199 }
200 else OSLibGpiQueryCurrentPosition(pHps,&ptl);
201
202 UINT align = GetTextAlign(hdc);
203 LONG pmHAlign,pmVAlign;
204
205#if 0
206 //SvL: This code is broken. TODO: Investigate
207 //CB: TA_RIGHT not supported by PM, only TA_CENTER and TA_LEFT
208 if ((align & 0x6) == TA_RIGHT)
209 {
210 BOOL rc;
211 PPOINTLOS2 pts = (PPOINTLOS2)malloc((cbCount+1)*sizeof(POINTLOS2));
212
213 rc = OSLibGpiQueryCharStringPosAt(pHps,&ptl,flOptions & CHSOS_VECTOR,cbCount,lpszString,lpDx,pts);
214 if(rc) {
215 for(int i=0;i<cbCount+1;i++) {
216 dprintf(("OSLibGpiQueryCharStringPosAt %d (%d,%d)", pts[i].x, pts[i].y));
217 }
218 ptl.x -= pts[cbCount].x-pts[0].x;
219 }
220 free(pts);
221 }
222#endif
223
224 if (lprc && ((align & 0x18) == TA_BASELINE))
225 {
226 //CB: if TA_BASELINE is set, GPI doesn't fill rect
227 // TA_BOTTOM fills rect
228 OSLibGpiQueryTextAlignment(pHps,&pmHAlign,&pmVAlign);
229 OSLibGpiSetTextAlignment(pHps,pmHAlign,(pmVAlign & ~TAOS_BASE) | TAOS_BOTTOM);
230 }
231
232#ifdef INVERT
233 ptl.y += getWorldYDeltaFor1Pixel(pHps);
234#else
235 ptl.y -= getWorldYDeltaFor1Pixel(pHps);
236
237 int vertAdjust = 0;
238 if ((pHps->taMode & 0x18) != TA_TOP)
239 {
240 vertAdjust = OSLibGpiQueryFontMaxHeight(pHps->hps);
241 }
242 ptl.y -= vertAdjust;
243#endif
244
245 hits = OSLibGpiCharStringPosAt(pHps,&ptl,&pmRect,flOptions,cbCount,lpszString,lpDx);
246
247 if (lprc && ((align & 0x18) == TA_BASELINE))
248 OSLibGpiSetTextAlignment(pHps,pmHAlign,pmVAlign);
249
250 if(hits == GPIOS_ERROR) {
251 dprintf(("InternalTextOutA: OSLibGpiCharStringPosAt returned GPIOS_ERROR"));
252#ifdef INVERT_SETYINVERSION
253 GpiEnableYInversion(pHps->hps, oldyinv);
254#endif
255 return FALSE;
256 }
257
258 if (getAlignUpdateCP(pHps))
259 {
260 OSLibGpiQueryCurrentPosition(pHps,&ptl);
261 ptl.y -= getWorldYDeltaFor1Pixel(pHps);
262#ifndef INVERT
263 ptl.y += vertAdjust;
264#endif
265 OSLibGpiSetCurrentPosition(pHps,&ptl);
266 }
267
268#ifdef INVERT_SETYINVERSION
269 GpiEnableYInversion(pHps->hps, oldyinv);
270#endif
271 return TRUE;
272}
273//******************************************************************************
274//******************************************************************************
275BOOL InternalTextOutW(HDC hdc,int X,int Y,UINT fuOptions,CONST RECT *lprc,LPCWSTR lpszString,INT cbCount,CONST INT *lpDx,BOOL IsExtTextOut)
276{
277 char *astring = NULL;
278 BOOL rc;
279
280 if(cbCount == -1) {
281 astring = UnicodeToAsciiString((LPWSTR)lpszString);
282 }
283 else
284 if(cbCount >= 0) {
285 int n = WideCharToMultiByte( CP_ACP, 0, lpszString, cbCount, 0, 0, NULL, NULL ) + 1;
286
287 astring = (char *)HEAP_malloc( n );
288 UnicodeToAsciiN((LPWSTR)lpszString, astring, n );
289 }
290
291 rc = InternalTextOutA(hdc,X,Y,fuOptions,lprc,(LPCSTR)astring, strlen( astring ),lpDx,IsExtTextOut);
292 if(astring) {
293 FreeAsciiString(astring);
294 }
295
296 return(rc);
297}
298//******************************************************************************
299//******************************************************************************
300BOOL WIN32API ExtTextOutA(HDC hdc,int X,int Y,UINT fuOptions,CONST RECT *lprc,LPCSTR lpszString,UINT cbCount,CONST INT *lpDx)
301{
302 LPSTR astring = NULL;
303 LPCSTR aCstring = lpszString;
304 BOOL rc;
305
306 /* no guarantee for zeroterminated text in lpszString, found in "PuTTY A Free Win32 Telnet SSH Client" */
307 if (cbCount >= 0)
308 {
309 astring = (char *)malloc(cbCount+1);
310 memcpy(astring, lpszString, cbCount);
311 astring[cbCount] = '\0';
312 aCstring = astring;
313 }
314 if(lprc)
315 {
316 dprintf(("GDI32: ExtTextOutA %x %s (%d,%d) %x %d %x rect (%d,%d)(%d,%d)", hdc, /*lpszString*/ aCstring, X, Y, fuOptions, cbCount, lpDx, lprc->left, lprc->top, lprc->right, lprc->bottom));
317 }
318 else dprintf(("GDI32: ExtTextOutA %x %s (%d,%d) %x %d %x", hdc, /*lpszString*/ aCstring, X, Y, fuOptions, cbCount, lpDx));
319
320 rc = InternalTextOutA(hdc, X, Y, fuOptions, lprc, aCstring, cbCount, lpDx, TRUE);
321
322 if(astring)
323 free(astring);
324
325 return(rc);
326}
327//******************************************************************************
328//******************************************************************************
329BOOL WIN32API ExtTextOutW(HDC hdc,int X,int Y,UINT fuOptions,CONST RECT *lprc,LPCWSTR lpszString,UINT cbCount,CONST int *lpDx)
330{
331 if(lprc) {
332 dprintf(("GDI32: ExtTextOutW %x %ls (%d,%d) %x %d %x rect (%d,%d)(%d,%d)", hdc, lpszString, X, Y, fuOptions, cbCount, lpDx, lprc->left, lprc->top, lprc->right, lprc->bottom));
333 }
334 else dprintf(("GDI32: ExtTextOutW %x %ls (%d,%d) %x %d %x", hdc, lpszString, X, Y, fuOptions, cbCount, lpDx));
335 return InternalTextOutW(hdc, X, Y, fuOptions, lprc, lpszString, cbCount, lpDx, TRUE);
336}
337//******************************************************************************
338//******************************************************************************
339BOOL WIN32API TextOutA(HDC hdc,int nXStart,int nYStart,LPCSTR lpszString,int cbString)
340{
341 dprintf(("GDI32: TextOutA %x (%d,%d) %d %.*s", hdc, nXStart, nYStart, cbString, cbString, lpszString));
342 return InternalTextOutA(hdc,nXStart,nYStart,0,NULL,lpszString,cbString,NULL,FALSE);
343}
344//******************************************************************************
345//******************************************************************************
346BOOL WIN32API TextOutW(HDC hdc,int nXStart,int nYStart,LPCWSTR lpszString,int cbString)
347{
348 dprintf(("GDI32: TextOutW %x (%d,%d) %d %.*ls", hdc, nXStart, nYStart, cbString, cbString, lpszString));
349 return InternalTextOutW(hdc,nXStart,nYStart,0,NULL,lpszString,cbString,NULL,FALSE);
350}
351//******************************************************************************
352//******************************************************************************
353BOOL WIN32API PolyTextOutA(HDC hdc,POLYTEXTA *pptxt,int cStrings)
354{
355 dprintf(("GDI32: PolyTextOutA %x %x %d", hdc, pptxt, cStrings));
356
357 for (INT x = 0;x < cStrings;x++)
358 {
359 BOOL rc;
360
361 rc = InternalTextOutA(hdc,pptxt[x].x,pptxt[x].y,pptxt[x].uiFlags,&pptxt[x].rcl,pptxt[x].lpstr,pptxt[x].n,pptxt[x].pdx,TRUE);
362 if (!rc) return FALSE;
363 }
364
365 return TRUE;
366}
367//******************************************************************************
368//******************************************************************************
369BOOL WIN32API PolyTextOutW(HDC hdc,POLYTEXTW *pptxt,int cStrings)
370{
371 dprintf(("GDI32: PolyTextOutW %x %x %d", hdc, pptxt, cStrings));
372
373 for (INT x = 0;x < cStrings;x++)
374 {
375 BOOL rc;
376
377 rc = InternalTextOutW(hdc,pptxt[x].x,pptxt[x].y,pptxt[x].uiFlags,&pptxt[x].rcl,pptxt[x].lpstr,pptxt[x].n,pptxt[x].pdx,TRUE);
378 if (!rc) return FALSE;
379 }
380
381 return TRUE;
382}
383//******************************************************************************
384//******************************************************************************
385BOOL WIN32API GetTextExtentPointA(HDC hdc, LPCTSTR lpsz, int cbString,
386 LPSIZE lpsSize)
387{
388#if 1
389 dprintf(("GDI32: GetTextExtentPointA %x %.*s %d", hdc, cbString, lpsz, cbString));
390
391 if(lpsz == NULL || cbString < 0 || lpsSize == NULL)
392 {
393 dprintf(("!WARNING!: GDI32: GetTextExtentPointA invalid parameter!"));
394 SetLastError(ERROR_INVALID_PARAMETER);
395 return FALSE;
396 }
397
398 lpsSize->cx = 0;
399 lpsSize->cy = 0;
400
401 // Verified with NT4, SP6
402 if(cbString == 0)
403 {
404 dprintf(("GDI32: GetTextExtentPointA cbString == 0"));
405 SetLastError(ERROR_SUCCESS);
406 return TRUE;
407 }
408
409 //SvL: This works better than the code below. Can been seen clearly
410 // in the Settings dialog box of VirtualPC. Strings are clipped.
411 // (e.g.: Hard Disk 1 -> Hard Disk)
412 BOOL rc = O32_GetTextExtentPoint(hdc, lpsz, cbString, lpsSize);
413 if(rc) {
414 dprintf(("GDI32: GetTextExtentPointA returned (%d,%d)", lpsSize->cx, lpsSize->cy));
415 SetLastError(ERROR_SUCCESS);
416 return TRUE;
417 }
418 return FALSE;
419#else
420 BOOL rc;
421 POINTLOS2 pts[TXTBOXOS_COUNT];
422 POINTLOS2 widthHeight = { 0, 0};
423 pDCData pHps = (pDCData)OSLibGpiQueryDCData((HPS)hdc);
424
425 dprintf(("GDI32: GetTextExtentPointA %s\n", lpsz));
426 if(pHps == NULL)
427 {
428 SetLastError(ERROR_INVALID_HANDLE);
429 return FALSE;
430 }
431
432 if(lpsz == NULL || cbString < 0 || lpsSize == NULL)
433 {
434 SetLastError(ERROR_INVALID_PARAMETER);
435 return FALSE;
436 }
437
438 lpsSize->cx = 0;
439 lpsSize->cy = 0;
440
441 // Verified with NT4, SP6
442 if(cbString == 0)
443 {
444 SetLastError(ERROR_SUCCESS);
445 return TRUE;
446 }
447 if(cbString > 512)
448 {
449 DWORD cbStringNew;
450 SIZE newSize;
451
452 dprintf(("WARNING: string longer than 512 chars; splitting up"));
453 lpsSize->cx = 0;
454 lpsSize->cy = 0;
455 while(cbString) {
456 cbStringNew = min(500, cbString);
457 rc = GetTextExtentPointA(hdc, lpsz, cbStringNew, &newSize);
458 if(rc == FALSE) {
459 return FALSE;
460 }
461 lpsSize->cx += newSize.cx;
462 lpsSize->cy = max(newSize.cy, lpsSize->cy);
463 lpsz += cbStringNew;
464 cbString -= cbStringNew;
465 }
466 return TRUE;
467 }
468
469 rc = OSLibGpiQueryTextBox(pHps, cbString, lpsz, TXTBOXOS_COUNT, pts);
470 if(rc == FALSE)
471 {
472 SetLastError(ERROR_INVALID_PARAMETER); //todo wrong error
473 return FALSE;
474 }
475 calcDimensions(pts, &widthHeight);
476 lpsSize->cx = widthHeight.x;
477 lpsSize->cy = widthHeight.y;
478
479 if(pHps && pHps->isPrinter && pHps->hdc)
480 {//scale for printer dcs
481 LONG alArray[2];
482
483 if (OSLibDevQueryCaps(pHps, OSLIB_CAPS_HORIZONTAL_RESOLUTION, 2, &alArray[0]))
484 lpsSize->cx = lpsSize->cx * alArray[0] / alArray[1];
485 }
486
487 dprintf(("GDI32: GetTextExtentPointA %x %s %d returned %d (%d,%d)", hdc, lpsz, cbString, rc, lpsSize->cx, lpsSize->cy));
488 SetLastError(ERROR_SUCCESS);
489 return TRUE;
490#endif
491}
492//******************************************************************************
493//******************************************************************************
494BOOL WIN32API GetTextExtentPointW(HDC hdc,
495 LPCWSTR lpString,
496 int cbString,
497 PSIZE lpSize)
498{
499 char *astring;
500 int len;
501 BOOL rc;
502
503 if(lpString == NULL || cbString < 0 || lpSize == NULL)
504 {
505 dprintf(("!WARNING!: GDI32: GetTextExtentPointW invalid parameter!"));
506 SetLastError(ERROR_INVALID_PARAMETER);
507 return FALSE;
508 }
509
510 lpSize->cx = 0;
511 lpSize->cy = 0;
512
513 // Verified with NT4, SP6
514 if(cbString == 0)
515 {
516 dprintf(("GDI32: GetTextExtentPointW cbString == 0"));
517 SetLastError(ERROR_SUCCESS);
518 return TRUE;
519 }
520
521 dprintf(("GDI32: GetTextExtentPointW %x %.*ls %d %x", hdc, cbString, lpString, cbString, lpSize));
522
523 len = WideCharToMultiByte( CP_ACP, 0, lpString, cbString, 0, 0, NULL, NULL );
524 astring = (char *)malloc( len + 1 );
525 UnicodeToAsciiN(lpString, astring, len + 1 );
526 rc = GetTextExtentPointA(hdc, astring,
527 len, lpSize);
528
529 free(astring);
530 return(rc);
531}
532//******************************************************************************
533//******************************************************************************
534BOOL WIN32API GetTextExtentPoint32A( HDC hdc, LPCSTR lpsz, int cbString, PSIZE lpSize)
535{
536 return GetTextExtentPointA(hdc, lpsz, cbString, lpSize);
537}
538//******************************************************************************
539//******************************************************************************
540BOOL WIN32API GetTextExtentPoint32W(HDC hdc, LPCWSTR lpsz, int cbString, PSIZE lpSize)
541{
542 return GetTextExtentPointW(hdc, lpsz, cbString, lpSize);
543}
544//******************************************************************************
545//******************************************************************************
Note: See TracBrowser for help on using the repository browser.