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

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

DT: ExtTextOutA: copy string and force zero termination

File size: 16.5 KB
Line 
1/* $Id: text.cpp,v 1.33 2003-03-03 16:33:35 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) {
285 astring = (char *)HEAP_malloc(cbCount+1);
286 UnicodeToAsciiN((LPWSTR)lpszString, astring, cbCount+1);
287 astring[cbCount] = 0;
288 }
289 rc = InternalTextOutA(hdc,X,Y,fuOptions,lprc,(LPCSTR)astring,cbCount,lpDx,IsExtTextOut);
290 if(astring) {
291 FreeAsciiString(astring);
292 }
293
294 return(rc);
295}
296//******************************************************************************
297//******************************************************************************
298BOOL WIN32API ExtTextOutA(HDC hdc,int X,int Y,UINT fuOptions,CONST RECT *lprc,LPCSTR lpszString,UINT cbCount,CONST INT *lpDx)
299{
300 LPSTR astring = NULL;
301 LPCSTR aCstring = lpszString;
302 BOOL rc;
303
304 /* no guarantee for zeroterminated text in lpszString, found in "PuTTY A Free Win32 Telnet SSH Client" */
305 if (cbCount >= 0)
306 {
307 astring = (char *)malloc(cbCount+1);
308 memcpy(astring, lpszString, cbCount);
309 astring[cbCount] = '\0';
310 aCstring = astring;
311 }
312 if(lprc)
313 {
314 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));
315 }
316 else dprintf(("GDI32: ExtTextOutA %x %s (%d,%d) %x %d %x", hdc, /*lpszString*/ aCstring, X, Y, fuOptions, cbCount, lpDx));
317
318 rc = InternalTextOutA(hdc, X, Y, fuOptions, lprc, aCstring, cbCount, lpDx, TRUE);
319
320 if(astring)
321 free(astring);
322
323 return(rc);
324}
325//******************************************************************************
326//******************************************************************************
327BOOL WIN32API ExtTextOutW(HDC hdc,int X,int Y,UINT fuOptions,CONST RECT *lprc,LPCWSTR lpszString,UINT cbCount,CONST int *lpDx)
328{
329 if(lprc) {
330 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));
331 }
332 else dprintf(("GDI32: ExtTextOutW %x %ls (%d,%d) %x %d %x", hdc, lpszString, X, Y, fuOptions, cbCount, lpDx));
333 return InternalTextOutW(hdc, X, Y, fuOptions, lprc, lpszString, cbCount, lpDx, TRUE);
334}
335//******************************************************************************
336//******************************************************************************
337BOOL WIN32API TextOutA(HDC hdc,int nXStart,int nYStart,LPCSTR lpszString,int cbString)
338{
339 dprintf(("GDI32: TextOutA %x (%d,%d) %d %.*s", hdc, nXStart, nYStart, cbString, cbString, lpszString));
340 return InternalTextOutA(hdc,nXStart,nYStart,0,NULL,lpszString,cbString,NULL,FALSE);
341}
342//******************************************************************************
343//******************************************************************************
344BOOL WIN32API TextOutW(HDC hdc,int nXStart,int nYStart,LPCWSTR lpszString,int cbString)
345{
346 dprintf(("GDI32: TextOutW %x (%d,%d) %d %.*ls", hdc, nXStart, nYStart, cbString, cbString, lpszString));
347 return InternalTextOutW(hdc,nXStart,nYStart,0,NULL,lpszString,cbString,NULL,FALSE);
348}
349//******************************************************************************
350//******************************************************************************
351BOOL WIN32API PolyTextOutA(HDC hdc,POLYTEXTA *pptxt,int cStrings)
352{
353 dprintf(("GDI32: PolyTextOutA %x %x %d", hdc, pptxt, cStrings));
354
355 for (INT x = 0;x < cStrings;x++)
356 {
357 BOOL rc;
358
359 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);
360 if (!rc) return FALSE;
361 }
362
363 return TRUE;
364}
365//******************************************************************************
366//******************************************************************************
367BOOL WIN32API PolyTextOutW(HDC hdc,POLYTEXTW *pptxt,int cStrings)
368{
369 dprintf(("GDI32: PolyTextOutW %x %x %d", hdc, pptxt, cStrings));
370
371 for (INT x = 0;x < cStrings;x++)
372 {
373 BOOL rc;
374
375 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);
376 if (!rc) return FALSE;
377 }
378
379 return TRUE;
380}
381//******************************************************************************
382//******************************************************************************
383BOOL WIN32API GetTextExtentPointA(HDC hdc, LPCTSTR lpsz, int cbString,
384 LPSIZE lpsSize)
385{
386#if 1
387 dprintf(("GDI32: GetTextExtentPointA %x %.*s %d", hdc, cbString, lpsz, cbString));
388
389 if(lpsz == NULL || cbString < 0 || lpsSize == NULL)
390 {
391 dprintf(("!WARNING!: GDI32: GetTextExtentPointA invalid parameter!"));
392 SetLastError(ERROR_INVALID_PARAMETER);
393 return FALSE;
394 }
395
396 lpsSize->cx = 0;
397 lpsSize->cy = 0;
398
399 // Verified with NT4, SP6
400 if(cbString == 0)
401 {
402 dprintf(("GDI32: GetTextExtentPointA cbString == 0"));
403 SetLastError(ERROR_SUCCESS);
404 return TRUE;
405 }
406
407 //SvL: This works better than the code below. Can been seen clearly
408 // in the Settings dialog box of VirtualPC. Strings are clipped.
409 // (e.g.: Hard Disk 1 -> Hard Disk)
410 BOOL rc = O32_GetTextExtentPoint(hdc, lpsz, cbString, lpsSize);
411 if(rc) {
412 dprintf(("GDI32: GetTextExtentPointA returned (%d,%d)", lpsSize->cx, lpsSize->cy));
413 SetLastError(ERROR_SUCCESS);
414 return TRUE;
415 }
416 return FALSE;
417#else
418 BOOL rc;
419 POINTLOS2 pts[TXTBOXOS_COUNT];
420 POINTLOS2 widthHeight = { 0, 0};
421 pDCData pHps = (pDCData)OSLibGpiQueryDCData((HPS)hdc);
422
423 dprintf(("GDI32: GetTextExtentPointA %s\n", lpsz));
424 if(pHps == NULL)
425 {
426 SetLastError(ERROR_INVALID_HANDLE);
427 return FALSE;
428 }
429
430 if(lpsz == NULL || cbString < 0 || lpsSize == NULL)
431 {
432 SetLastError(ERROR_INVALID_PARAMETER);
433 return FALSE;
434 }
435
436 lpsSize->cx = 0;
437 lpsSize->cy = 0;
438
439 // Verified with NT4, SP6
440 if(cbString == 0)
441 {
442 SetLastError(ERROR_SUCCESS);
443 return TRUE;
444 }
445 if(cbString > 512)
446 {
447 DWORD cbStringNew;
448 SIZE newSize;
449
450 dprintf(("WARNING: string longer than 512 chars; splitting up"));
451 lpsSize->cx = 0;
452 lpsSize->cy = 0;
453 while(cbString) {
454 cbStringNew = min(500, cbString);
455 rc = GetTextExtentPointA(hdc, lpsz, cbStringNew, &newSize);
456 if(rc == FALSE) {
457 return FALSE;
458 }
459 lpsSize->cx += newSize.cx;
460 lpsSize->cy = max(newSize.cy, lpsSize->cy);
461 lpsz += cbStringNew;
462 cbString -= cbStringNew;
463 }
464 return TRUE;
465 }
466
467 rc = OSLibGpiQueryTextBox(pHps, cbString, lpsz, TXTBOXOS_COUNT, pts);
468 if(rc == FALSE)
469 {
470 SetLastError(ERROR_INVALID_PARAMETER); //todo wrong error
471 return FALSE;
472 }
473 calcDimensions(pts, &widthHeight);
474 lpsSize->cx = widthHeight.x;
475 lpsSize->cy = widthHeight.y;
476
477 if(pHps && pHps->isPrinter && pHps->hdc)
478 {//scale for printer dcs
479 LONG alArray[2];
480
481 if (OSLibDevQueryCaps(pHps, OSLIB_CAPS_HORIZONTAL_RESOLUTION, 2, &alArray[0]))
482 lpsSize->cx = lpsSize->cx * alArray[0] / alArray[1];
483 }
484
485 dprintf(("GDI32: GetTextExtentPointA %x %s %d returned %d (%d,%d)", hdc, lpsz, cbString, rc, lpsSize->cx, lpsSize->cy));
486 SetLastError(ERROR_SUCCESS);
487 return TRUE;
488#endif
489}
490//******************************************************************************
491//******************************************************************************
492BOOL WIN32API GetTextExtentPointW(HDC hdc,
493 LPCWSTR lpString,
494 int cbString,
495 PSIZE lpSize)
496{
497 char *astring;
498 BOOL rc;
499
500 if(lpString == NULL || cbString < 0 || lpSize == NULL)
501 {
502 dprintf(("!WARNING!: GDI32: GetTextExtentPointW invalid parameter!"));
503 SetLastError(ERROR_INVALID_PARAMETER);
504 return FALSE;
505 }
506
507 lpSize->cx = 0;
508 lpSize->cy = 0;
509
510 // Verified with NT4, SP6
511 if(cbString == 0)
512 {
513 dprintf(("GDI32: GetTextExtentPointW cbString == 0"));
514 SetLastError(ERROR_SUCCESS);
515 return TRUE;
516 }
517
518 dprintf(("GDI32: GetTextExtentPointW %x %.*ls %d %x", hdc, cbString, lpString, cbString, lpSize));
519
520 astring = (char *)malloc((cbString+1)*sizeof(WCHAR));
521 UnicodeToAsciiN(lpString, astring, cbString+1);
522
523 rc = GetTextExtentPointA(hdc, astring,
524 cbString, lpSize);
525
526 free(astring);
527 return(rc);
528}
529//******************************************************************************
530//******************************************************************************
531BOOL WIN32API GetTextExtentPoint32A( HDC hdc, LPCSTR lpsz, int cbString, PSIZE lpSize)
532{
533 return GetTextExtentPointA(hdc, lpsz, cbString, lpSize);
534}
535//******************************************************************************
536//******************************************************************************
537BOOL WIN32API GetTextExtentPoint32W(HDC hdc, LPCWSTR lpsz, int cbString, PSIZE lpSize)
538{
539 return GetTextExtentPointW(hdc, lpsz, cbString, lpSize);
540}
541//******************************************************************************
542//******************************************************************************
Note: See TracBrowser for help on using the repository browser.