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

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

bug fix

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