source: trunk/src/kernel/qfontengine_pm.cpp@ 10

Last change on this file since 10 was 8, checked in by dmik, 20 years ago

Transferred Qt for OS/2 version 3.3.1-rc5 sources from the CVS

  • Property svn:keywords set to Id
File size: 32.9 KB
Line 
1/****************************************************************************
2** $Id: qfontengine_pm.cpp 8 2005-11-16 19:36:46Z dmik $
3**
4** ???
5**
6** Copyright (C) 2003 Trolltech AS. All rights reserved.
7** Copyright (C) 2004 Norman ASA. Initial OS/2 Port.
8** Copyright (C) 2005 netlabs.org. Further OS/2 Development.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qfontengine_p.h"
39#include <qglobal.h>
40#include "qt_os2.h"
41#include "qapplication_p.h"
42
43#include <qpaintdevice.h>
44#include <qpainter.h>
45//@@TODO (dmik): need?
46//#include <limits.h>
47//#include <math.h>
48
49#include <private/qunicodetables_p.h>
50#include <qbitmap.h>
51
52#include <qthreadstorage.h>
53
54//@@TODO (dmik): need?
55//#ifndef M_PI
56//#define M_PI 3.14159265358979
57//#endif
58
59// per-thread unique screen ps to perform font operations
60
61//@@TODO (dmik): optimize: use small mem hps'es 1x1 px instead of screen ps?
62class QDisplayPS
63{
64public:
65 QDisplayPS() { hps = WinGetScreenPS( HWND_DESKTOP ); }
66 ~QDisplayPS() { WinReleasePS( hps ); }
67 HPS hps;
68};
69static QThreadStorage<QDisplayPS *> display_ps;
70
71
72//@@TODO (dmik): remove?
73//// defined in qtextengine_win.cpp
74//typedef void *SCRIPT_CACHE;
75//typedef HRESULT (WINAPI *fScriptFreeCache)( SCRIPT_CACHE *);
76//extern fScriptFreeCache ScriptFreeCache;
77
78
79//@@TODO (dmik): remove?
80//static unsigned char *getCMap( HDC hdc, bool & );
81//static Q_UINT16 getGlyphIndex( unsigned char *table, unsigned short unicode );
82
83
84//@@TODO (dmik): remove?
85//HDC shared_dc = 0; // common dc for all fonts
86//static HFONT shared_dc_font = 0; // used by Windows 95/98
87//static HFONT stock_sysfont = 0;
88//
89//static inline HFONT systemFont()
90//{
91// if ( stock_sysfont == 0 )
92// stock_sysfont = (HFONT)GetStockObject(SYSTEM_FONT);
93// return stock_sysfont;
94//}
95
96// general font engine
97
98QFontEngine::~QFontEngine()
99{
100 hps = 0;
101 delete pfm;
102//@@TODO (dmik): remove...
103// QT_WA( {
104// if ( hdc ) { // one DC per font (Win NT)
105// //SelectObject( hdc, systemFont() );
106// if ( !stockFont )
107// DeleteObject( hfont );
108// if ( !paintDevice )
109// ReleaseDC( 0, hdc );
110// hdc = 0;
111// hfont = 0;
112// }
113// } , {
114// if ( hfont ) { // shared DC (Windows 95/98)
115// if ( shared_dc_font == hfont ) { // this is the current font
116// Q_ASSERT( shared_dc != 0 );
117// SelectObject( shared_dc, systemFont() );
118// shared_dc_font = 0;
119// }
120// if ( !stockFont )
121// DeleteObject( hfont );
122// hfont = 0;
123// }
124// } );
125// delete [] cmap;
126//
127// // for Uniscribe
128// if ( ScriptFreeCache )
129// ScriptFreeCache( &script_cache );
130}
131
132int QFontEngine::lineThickness() const
133{
134//@@TODO (dmik): values from FONTMETRICS are not always good (line is too
135// thick or too close to glyphs). The algorithm below is not always perfect
136// either. Which one to leave?
137// // ad hoc algorithm
138// int score = fontDef.weight * fontDef.pixelSize;
139// int lw = score / 700;
140//
141// // looks better with thicker line for small pointsizes
142// if ( lw < 2 && score >= 1050 ) lw = 2;
143// if ( lw == 0 ) lw = 1;
144//
145// return lw;
146 return pfm->lUnderscoreSize;
147}
148
149int QFontEngine::underlinePosition() const
150{
151//@@TODO (dmik): values from FONTMETRICS are not always good (line is too
152// thick or too close to glyphs). The algorithm below is not always perfect
153// either. Which one to leave?
154// int pos = ( ( lineThickness() * 2 ) + 3 ) / 6;
155 int pos = pfm->lUnderscorePosition;
156 // ensure one pixel between baseline and underline
157 return pos > 1 ? pos : 2;
158}
159
160HPS QFontEngine::ps() const
161{
162 // if hps is not zero this means a printer font.
163 // NOTE: such (printer) font engines can be currently created only by
164 // QPainter::updateFont() and they are removed from the font cache by
165 // QFontCache::cleanupPrinterFonts() that is called by QPainter::end(),
166 // so it is safe to store only a hps of the printer paint device instead
167 // the whole QPaintDevice object (these font engines cannot live after
168 // the printer paint device is destroyed -- they are destroyed first,
169 // when the painting has ended on a particular printer device).
170
171 HPS ps = hps;
172 if ( !ps ) {
173 if ( !display_ps.hasLocalData() )
174 display_ps.setLocalData( new QDisplayPS );
175 ps = display_ps.localData()->hps;
176 }
177 selectTo( ps );
178 return ps;
179}
180
181static inline void uint2STR8( uint num, PSTR8 str )
182{
183 uint *p = (uint *) str;
184 *(p++) = (num & 0x0F0F0F0F) + 0x41414141;
185 *p = ((num >> 4) & 0x0F0F0F0F) + 0x41414141;
186}
187
188static inline uint STR82uint( PSTR8 str )
189{
190 uint *p = (uint *) str;
191 uint num = (*(p++)) - 0x41414141;
192 num |= ((*p) - 0x41414141) << 4;
193 return num;
194}
195
196void QFontEngine::selectTo( HPS ps ) const
197{
198 // innotek ft2lib 2.40 release 1 has a strange bug: when we pass the STR8
199 // identifier to GpiCreateLogFont() with the fourth char being zero it
200 // causes a trap. So we use uint2STR8() to convert pointers to a string
201 // containing 8 uppercase letters instead of passing pointers directly.
202
203 STR8 id;
204 FATTRS dummy;
205 uint2STR8( 0, &id );
206 GpiQueryLogicalFont( ps, LCID_QTFont, &id, &dummy, sizeof(FATTRS) );
207 if ( STR82uint( &id ) != (uint) this ) {
208#if 0
209 qDebug( "QFontEngine::selectTo: selecting font '%i:%i.%s' to %08lX",
210 fontDef.pixelSize, fontDef.pointSize/10, fa.szFacename, ps );
211#endif
212 uint2STR8( (uint) this, &id );
213 GpiCreateLogFont( ps, &id, LCID_QTFont, &fa );
214 GpiSetCharSet( ps, LCID_QTFont );
215 if ( fa.fsFontUse & FATTR_FONTUSE_OUTLINE ) {
216 SIZEF sz;
217 sz.cy = MAKEFIXED( fontDef.pixelSize, 0 );
218 sz.cx = sz.cy;
219 GpiSetCharBox( ps, &sz );
220 }
221 }
222#if 0
223 else {
224 qDebug( "QFontEngine::selectTo: font '%i:%i.%s' is already selected to %08lX",
225 fontDef.pixelSize, fontDef.pointSize/10, fa.szFacename, ps );
226 }
227#endif
228}
229
230//@@TODO (dmik): remove?
231//HDC QFontEngine::dc() const
232//{
233// if ( hdc || (qt_winver & Qt::WV_NT_based) ) // either NT_based or Printer
234// return hdc;
235// Q_ASSERT( shared_dc != 0 && hfont != 0 );
236// if ( shared_dc_font != hfont ) {
237// SelectObject( shared_dc, hfont );
238// shared_dc_font = hfont;
239// }
240// return shared_dc;
241//}
242
243//@@TODO (dmik): remove?
244//void QFontEngine::getCMap()
245//{
246// QT_WA( {
247// ttf = (bool)(tm.w.tmPitchAndFamily & TMPF_TRUETYPE);
248// } , {
249// ttf = (bool)(tm.a.tmPitchAndFamily & TMPF_TRUETYPE);
250// } );
251// HDC hdc = dc();
252// SelectObject( hdc, hfont );
253// bool symb = false;
254// cmap = ttf ? ::getCMap( hdc, symb ) : 0;
255// if ( !cmap ) {
256// ttf = false;
257// symb = false;
258// }
259// symbol = symb;
260// script_cache = 0;
261//}
262
263//@@TODO (dmik): remove
264//void QFontEngine::getGlyphIndexes( const QChar *ch, int numChars, glyph_t *glyphs, bool mirrored ) const
265//{
266// if ( mirrored ) {
267// if ( symbol ) {
268// while( numChars-- ) {
269// *glyphs = getGlyphIndex(cmap, ch->unicode() );
270// if(!*glyphs && ch->unicode() < 0x100)
271// *glyphs = getGlyphIndex(cmap, ch->unicode()+0xf000 );
272// glyphs++;
273// ch++;
274// }
275// } else if ( ttf ) {
276// while( numChars-- ) {
277// *glyphs = getGlyphIndex(cmap, ::mirroredChar(*ch).unicode() );
278// glyphs++;
279// ch++;
280// }
281// } else {
282// while( numChars-- ) {
283// *glyphs = ::mirroredChar(*ch).unicode();
284// glyphs++;
285// ch++;
286// }
287// }
288// } else {
289// if ( symbol ) {
290// while( numChars-- ) {
291// *glyphs = getGlyphIndex(cmap, ch->unicode() );
292// if(!*glyphs && ch->unicode() < 0x100)
293// *glyphs = getGlyphIndex(cmap, ch->unicode()+0xf000 );
294// glyphs++;
295// ch++;
296// }
297// } else if ( ttf ) {
298// while( numChars-- ) {
299// *glyphs = getGlyphIndex(cmap, ch->unicode() );
300// glyphs++;
301// ch++;
302// }
303// } else {
304// while( numChars-- ) {
305// *glyphs = ch->unicode();
306// glyphs++;
307// ch++;
308// }
309// }
310// }
311//}
312
313QFontEnginePM::QFontEnginePM( HPS ps, PFATTRS pfa, int pixelSize, int pointSize )
314{
315 hps = ps;
316 fa = *pfa;
317 pfm = new FONTMETRICS;
318
319 fontDef.pixelSize = pixelSize;
320 fontDef.pointSize = pointSize;
321 // the rest of fontDef is initialized by QFontDatabase::findFont()
322
323 GpiQueryFontMetrics( this->ps(), sizeof(FONTMETRICS), pfm );
324
325 // cache cost here should be in bytes. it is converted to
326 // kbytes by QFontCache::increaseCost()
327//@@TODO (dmik): is this formula for cost ok?
328 cache_cost = pfm->lMaxBaselineExt * pfm->lAveCharWidth * 2000;
329
330 widthCache = new unsigned char [widthCacheSize];
331 memset( widthCache, 0, widthCacheSize );
332}
333
334//@@TODO (dmik): remove
335//QFontEngineWin::QFontEngineWin( const char * name, HDC _hdc, HFONT _hfont, bool stockFont, LOGFONT lf )
336//{
337// paintDevice = FALSE;
338// //qDebug("regular windows font engine created: font='%s', size=%d", name, lf.lfHeight);
339//
340// _name = name;
341//
342// hdc = _hdc;
343// hfont = _hfont;
344// logfont = lf;
345// SelectObject( dc(), hfont );
346// this->stockFont = stockFont;
347//
348// lbearing = SHRT_MIN;
349// rbearing = SHRT_MIN;
350//
351// BOOL res;
352// QT_WA( {
353// res = GetTextMetricsW( dc(), &tm.w );
354// } , {
355// res = GetTextMetricsA( dc(), &tm.a );
356// } );
357//#ifndef QT_NO_DEBUG
358// if ( !res )
359// qSystemWarning( "QFontPrivate: GetTextMetrics failed" );
360//#endif
361// cache_cost = tm.w.tmHeight * tm.w.tmAveCharWidth * 2000;
362// getCMap();
363//
364// useTextOutA = FALSE;
365//#ifndef Q_OS_TEMP
366// // TextOutW doesn't work for symbol fonts on Windows 95!
367// // since we're using glyph indices we don't care for ttfs about this!
368// if ( qt_winver == Qt::WV_95 && !ttf &&
369// ( _name == "Marlett" || _name == "Symbol" || _name == "Webdings" || _name == "Wingdings" ) )
370// useTextOutA = TRUE;
371//#endif
372// memset( widthCache, 0, sizeof(widthCache) );
373//}
374
375//@@TODO (dmik): current implementation of this fn uses the local8bit QChar
376// code as the glyph index, i.e. glyphs are just unicode chars converted to
377// 8 bit chars according to the current (system) code page. This will be
378// changed when all font-related code will be rewritten to support true unicode
379// (for example, by using innotek ft2lib, since native OS/2 unicode support
380// relative to text output using GPI is pretty buggy).
381QFontEngine::Error QFontEnginePM::stringToCMap( const QChar *str, int len, glyph_t *glyphs, advance_t *advances, int *nglyphs, bool mirrored ) const
382{
383 if ( *nglyphs < len ) {
384 *nglyphs = len;
385 return OutOfMemory;
386 }
387
388//@@TODO (dmik): mirrored is currently ignored.
389 Q_UNUSED(mirrored);
390
391 // convert chars to glyphs
392 QCString s = QConstString( str, len ).string().local8Bit();
393 for ( int i = 0; i < len; i++ ) {
394 glyphs[i] = (uchar) s[i];
395 }
396
397 if ( advances ) {
398 HPS ps = 0;
399 glyph_t glyph;
400 for( register int i = 0; i < len; i++ ) {
401 glyph = *(glyphs + i);
402 advances[i] = (glyph < widthCacheSize) ? widthCache[glyph] : 0;
403 // font-width cache failed
404 if ( !advances[i] ) {
405 if ( !ps ) ps = this->ps();
406 POINTL ptls [TXTBOX_COUNT];
407 GpiQueryTextBox( ps, 1, &s[i], TXTBOX_COUNT, ptls);
408 advances[i] = ptls[4].x;
409 // if glyph's within cache range, store it for later
410 if ( glyph < widthCacheSize && advances[i] < 0x100 )
411 ((QFontEnginePM *)this)->widthCache[glyph] = advances[i];
412 }
413 }
414 }
415
416 *nglyphs = len;
417 return NoError;
418
419//@@TODO (dmik): remove
420// if ( *nglyphs < len ) {
421// *nglyphs = len;
422// return OutOfMemory;
423// }
424//
425// getGlyphIndexes( str, len, glyphs, mirrored );
426//
427// if ( advances ) {
428// HDC hdc = dc();
429// unsigned int glyph;
430// int overhang = (qt_winver & Qt::WV_DOS_based) ? tm.a.tmOverhang : 0;
431// for( register int i = 0; i < len; i++ ) {
432// glyph = *(glyphs + i);
433// advances[i] = (glyph < widthCacheSize) ? widthCache[glyph] : 0;
434// // font-width cache failed
435// if ( !advances[i] ) {
436// SIZE size;
437// GetTextExtentPoint32W( hdc, (wchar_t *)str, 1, &size );
438// advances[i] = size.cx - overhang;
439// // if glyph's within cache range, store it for later
440// if ( glyph < widthCacheSize && (size.cx - overhang) < 0x100 )
441// ((QFontEngineWin *)this)->widthCache[glyph] = size.cx - overhang;
442// }
443// str++;
444// }
445// }
446//
447// *nglyphs = len;
448// return NoError;
449}
450
451// QRgb has the same RGB format (0xaarrggbb) as OS/2 uses (ignoring the
452// highest alpha byte) so we just mask alpha to get the valid OS/2 color.
453#define COLOR_VALUE(c) ((p->flags & QPainter::RGBColor) ? (c.rgb() & RGB_MASK) : c.pixel())
454
455// defined in qpaintdevice_pm.cpp
456extern const LONG qt_ropCodes_2ROP[];
457
458void QFontEnginePM::draw( QPainter *p, int x, int y, const QTextEngine *engine, const QScriptItem *si, int textFlags )
459{
460 HPS ps = p->handle();
461
462 glyph_t *glyphs = engine->glyphs( si );
463 advance_t *advances = engine->advances( si );
464 qoffset_t *offsets = engine->offsets( si );
465
466 /// @todo (dmik)
467 // glyphs here are just 8 bit chars (see stringToCMap()),
468 // and glyph_t is temporarly defined as unsigned char.
469 // it should be changed later.
470 PSZ cglyphs = (PSZ) glyphs;
471 /*
472 QConstString str( (QChar *)glyphs, si->num_glyphs );
473 QCString cglyphs = str.string().latin1();
474 */
475
476 // GPI version of the opaque rectangle below the text is rather strange,
477 // so we draw it ourselves
478 if ( p->backgroundMode() == Qt::OpaqueMode ) {
479 LONG oldMix = GpiQueryMix( ps );
480 GpiSetMix( ps, FM_LEAVEALONE );
481 // use drawRect to have the rectangle properly transformed
482 /// @todo (dmik)
483 // we don't add 1 to si->ascent + si->descent to exactly match
484 // QFontMetrics::boundingRect(). This stuff needs to be reviewed
485 // and synchronized everywhere (first we should define
486 // is total_height = acsent + descent or greater by one?).
487 // This also relates to the baseline issue below.
488 p->drawRect( x, y - si->ascent, si->width, si->ascent + si->descent );
489 GpiSetMix( ps, oldMix );
490 }
491
492 if ( !(pfm->fsDefn & FM_DEFN_OUTLINE) && p->txop > QPainter::TxTranslate ) {
493 // GPI is not capable (?) to scale/shear/rotate bitmap fonts,
494 // so we do it by hand
495 QRect bbox( 0, 0, si->width, si->ascent + si->descent + 1 );
496 int w = bbox.width(), h = bbox.height();
497 if ( w == 0 || h == 0 )
498 return;
499 QWMatrix tmat = QPixmap::trueMatrix( p->xmat, w, h );
500 QBitmap bm( w, h, TRUE );
501 QPainter paint;
502
503 // draw text into the bitmap
504 paint.begin( &bm );
505 // select the proper font manually
506 paint.clearf( QPainter::DirtyFont );
507 selectTo ( paint.handle() );
508 draw( &paint, 0, si->ascent, engine, si, textFlags );
509 paint.end();
510 // transform bitmap
511 QBitmap wx_bm = bm.xForm( tmat );
512 if ( wx_bm.isNull() )
513 return;
514
515 // compute the position of the bitmap
516 double fx = x, fy = y, nfx, nfy;
517 p->xmat.map( fx,fy, &nfx, &nfy );
518 double tfx = 0., tfy = si->ascent, dx, dy;
519 tmat.map( tfx, tfy, &dx, &dy );
520 x = qRound( nfx - dx );
521 y = qRound( nfy - dy );
522
523 // flip y coordinate of the bitmap
524 if ( p->devh )
525 y = p->devh - (y + wx_bm.height());
526
527 POINTL ptls[] = { { x, y }, { x + wx_bm.width(), y + wx_bm.height() },
528 { 0, 0 } };
529
530 // leave bitmap background transparent when blitting
531 LONG oldBackMix = GpiQueryBackMix( p->handle() );
532 GpiSetBackMix( p->handle(), BM_SRCTRANSPARENT );
533
534 GpiBitBlt( p->handle(), wx_bm.handle(), 3, ptls,
535 qt_ropCodes_2ROP[p->rop], BBO_IGNORE );
536 GpiSetBackMix( p->handle(), oldBackMix );
537
538 return;
539 }
540
541 if ( p->testf(QPainter::DirtyFont) )
542 p->updateFont();
543
544 // leave text background transparent -- we've already drawn it if OpaqueMode
545 LONG oldBackMix = GpiQueryBackMix( ps );
546 GpiSetBackMix( ps, BM_LEAVEALONE );
547
548 /// @todo (dmik)
549 // OS/2 GPI thinks that regular font letters (without any lower elements)
550 // should "overlap" the baseline, while Qt/Win32 thinks they should "sit"
551 // on it. For now, we simply mimic the Qt/Win32 behavior (for compatibilty)
552 // by correcting the y coordinate by one pixel. This is rather stupid.
553 // The proper way is to review all the code that deals with
554 // ascents/descents, bounding boxes/rects etc. (currently, all this
555 /// stuff has various issues regarding to misaligmnent between the opaque
556 // rectangle of the char and its bounding box etc.) and make a correct
557 // desicion afterwards... Btw, Qt/Win32 is rather buggy here too.
558 y--;
559
560 // prepare transformations
561 bool nativexform = FALSE;
562 LONG ySign = 1;
563
564 if ( p->txop == QPainter::TxTranslate ) {
565 p->map( x, y, &x, &y );
566 } else if ( p->txop > QPainter::TxTranslate ) {
567 y = -y;
568 ySign = -1;
569 nativexform = p->setNativeXForm( TRUE /* assumeYNegation */ );
570 if( !nativexform )
571 return;
572 }
573
574 ULONG options = 0;
575
576 // We draw underscores and strikeouts ourselves (since OS/2 font rasterizer
577 // usually does this very ugly, and sometimes it doesn't work at all with
578 // some fonts (i.e. WarpSans)).
579 /*
580 if ( textFlags & Qt::Underline ) options |= CHS_UNDERSCORE;
581 if ( textFlags & Qt::StrikeOut ) options |= CHS_STRIKEOUT;
582 */
583
584 int xo = x;
585 POINTL ptl;
586
587 if ( !(si->analysis.bidiLevel % 2) ) {
588 bool haveOffsets = FALSE;
589 int w = 0;
590 for( int i = 0; i < si->num_glyphs; i++ ) {
591 if ( offsets[i].x || offsets[i].y ) {
592 haveOffsets = TRUE;
593 break;
594 }
595 w += advances[i];
596 }
597
598 if ( haveOffsets ) {
599 for( int i = 0; i < si->num_glyphs; i++ ) {
600 char chr = *glyphs;
601 ptl.x = x + offsets->x;
602 ptl.y = y + ySign * offsets->y;
603 // flip y coordinate
604 if ( !nativexform && p->devh )
605 ptl.y = p->devh - (ptl.y + 1);
606 GpiCharStringPosAt( ps, &ptl, NULL, options, 1, &chr, NULL );
607 x += *advances;
608 glyphs++;
609 offsets++;
610 advances++;
611 }
612 } else {
613 // fast path
614 ptl.x = x;
615 ptl.y = y;
616 // flip y coordinate
617 if ( !nativexform && p->devh )
618 ptl.y = p->devh - (ptl.y + 1);
619 GpiCharStringPosAt( ps, &ptl, NULL, options | CHS_VECTOR,
620 si->num_glyphs, cglyphs, (PLONG) advances );
621 x += w;
622 }
623 } else {
624 offsets += si->num_glyphs;
625 advances += si->num_glyphs;
626 glyphs += si->num_glyphs;
627 for( int i = 0; i < si->num_glyphs; i++ ) {
628 glyphs--;
629 offsets--;
630 advances--;
631 char chr = *glyphs;
632 ptl.x = x + offsets->x;
633 ptl.y = y + ySign * offsets->y;
634 // flip y coordinate
635 if ( !nativexform && p->devh )
636 ptl.y = p->devh - (ptl.y + 1);
637 GpiCharStringPosAt( ps, &ptl, NULL, options, 1, &chr, NULL );
638 x += *advances;
639 }
640 }
641
642 if ( textFlags & (Qt::Overline | Qt::Underline | Qt::StrikeOut) ) {
643 AREABUNDLE oldAb, ab;
644 const LONG aa = ABB_COLOR | ABB_SET | ABB_SYMBOL;
645 GpiQueryAttrs( ps, PRIM_AREA, aa, &oldAb );
646 ab.lColor = COLOR_VALUE( p->cpen.color() );
647 ab.usSet = LCID_DEFAULT;
648 ab.usSymbol = PATSYM_SOLID;
649 GpiSetAttrs( ps, PRIM_AREA, aa, 0, &ab );
650
651 int lw = lineThickness() - 1; // inclusive
652 int lp;
653 // flip y coordinate
654 int yp = y;
655 if ( !nativexform && p->devh )
656 yp = p->devh - (yp + 1);
657 if ( textFlags & (Qt::Underline) ) {
658 ptl.x = xo;
659 ptl.y = yp - underlinePosition();
660 GpiMove( ps, &ptl );
661 ptl.x = x - 1; ptl.y -= lw;
662 GpiBox( ps, DRO_FILL, &ptl, 0, 0 );
663 }
664 if ( textFlags & (Qt::Overline) ) {
665 lp = ascent() + 1; // corresponds to QFontMetrics::overlinePos()
666 if ( !lp ) lp = 1;
667 ptl.x = xo;
668 ptl.y = yp + lp;
669 GpiMove( ps, &ptl );
670 ptl.x = x - 1; ptl.y -= lw;
671 GpiBox( ps, DRO_FILL, &ptl, 0, 0 );
672 }
673 if ( textFlags & (Qt::StrikeOut) ) {
674 lp = ascent() / 3; // corresponds to QFontMetrics::strikeOutPos()
675 if ( !lp ) lp = 1;
676 ptl.x = xo;
677 ptl.y = yp + lp;
678 GpiMove( ps, &ptl );
679 ptl.x = x - 1; ptl.y -= lw;
680 GpiBox( ps, DRO_FILL, &ptl, 0, 0 );
681 }
682 GpiSetAttrs( ps, PRIM_AREA, aa, 0, &oldAb );
683 }
684
685 if ( nativexform ) {
686 p->clearNativeXForm();
687 }
688
689 GpiSetBackMix( ps, oldBackMix );
690}
691
692glyph_metrics_t QFontEnginePM::boundingBox( const glyph_t *glyphs,
693 const advance_t *advances, const qoffset_t *offsets, int numGlyphs )
694{
695 Q_UNUSED( glyphs );
696 Q_UNUSED( offsets );
697
698 if ( numGlyphs == 0 )
699 return glyph_metrics_t();
700
701 int w = 0;
702 const advance_t *end = advances + numGlyphs;
703 while( end > advances )
704 w += *(--end);
705
706//@@TODO (dmik): look at usage of this fn, is the return correct?
707 return glyph_metrics_t(
708 0, -pfm->lMaxAscender, w, pfm->lMaxAscender + pfm->lMaxDescender, w, 0
709 );
710}
711
712glyph_metrics_t QFontEnginePM::boundingBox( glyph_t glyph )
713{
714//@@TODO (dmik): glyphs here are just 8 bit chars (see stringToCMap()),
715// it should be changed later.
716 POINTL ptls [TXTBOX_COUNT];
717 GpiQueryTextBox( ps(), 1, (char *)&glyph, TXTBOX_COUNT, ptls );
718 int minx = 0, miny = 0, maxx = 0, maxy = 0;
719 for ( int i = 0; i < 4; i++ ) {
720 minx = QMIN( minx, ptls[i].x );
721 miny = QMIN( miny, ptls[i].y );
722 maxx = QMAX( maxx, ptls[i].x );
723 maxy = QMAX( maxy, ptls[i].y );
724 }
725 return glyph_metrics_t(
726 minx, -maxy, maxx - minx + 1, maxy - miny + 1, ptls[4].x, -ptls[4].y
727 );
728
729//@@TODO (dmik): remove
730//#ifndef Q_OS_TEMP
731// GLYPHMETRICS gm;
732//
733// if( !ttf ) {
734// SIZE s;
735// WCHAR ch = glyph;
736// BOOL res = GetTextExtentPoint32W( dc(), &ch, 1, &s );
737// Q_UNUSED( res );
738// int overhang = (qt_winver & Qt::WV_DOS_based) ? tm.a.tmOverhang : 0;
739// return glyph_metrics_t( 0, -tm.a.tmAscent, s.cx, tm.a.tmHeight, s.cx-overhang, 0 );
740// } else {
741// DWORD res = 0;
742// MAT2 mat;
743// mat.eM11.value = mat.eM22.value = 1;
744// mat.eM11.fract = mat.eM22.fract = 0;
745// mat.eM21.value = mat.eM12.value = 0;
746// mat.eM21.fract = mat.eM12.fract = 0;
747// QT_WA( {
748// res = GetGlyphOutlineW( dc(), glyph, GGO_METRICS|GGO_GLYPH_INDEX, &gm, 0, 0, &mat );
749// } , {
750// res = GetGlyphOutlineA( dc(), glyph, GGO_METRICS|GGO_GLYPH_INDEX, &gm, 0, 0, &mat );
751// } );
752// if ( res != GDI_ERROR )
753// return glyph_metrics_t( gm.gmptGlyphOrigin.x, -gm.gmptGlyphOrigin.y,
754// gm.gmBlackBoxX, gm.gmBlackBoxY, gm.gmCellIncX, gm.gmCellIncY );
755// }
756//#endif
757// return glyph_metrics_t();
758}
759
760int QFontEnginePM::ascent() const
761{
762 return pfm->lMaxAscender;
763}
764
765int QFontEnginePM::descent() const
766{
767 return pfm->lMaxDescender;
768}
769
770int QFontEnginePM::leading() const
771{
772 return pfm->lExternalLeading;
773}
774
775int QFontEnginePM::maxCharWidth() const
776{
777 return pfm->lMaxCharInc;
778}
779
780//@@TODO (dmik): remove?
781//enum { max_font_count = 256 };
782//static const ushort char_table[] = {
783// 40,
784// 67,
785// 70,
786// 75,
787// 86,
788// 88,
789// 89,
790// 91,
791// 102,
792// 114,
793// 124,
794// 127,
795// 205,
796// 645,
797// 884,
798// 922,
799// 1070,
800// 12386,
801// 0
802//};
803//
804//static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
805
806
807int QFontEnginePM::minLeftBearing() const
808{
809//@@TODO (dmik): later
810 return 0;
811// if ( lbearing == SHRT_MIN )
812// minRightBearing(); // calculates both
813//
814// return lbearing;
815}
816
817int QFontEnginePM::minRightBearing() const
818{
819//@@TODO (dmik): later
820 return 0;
821//#ifdef Q_OS_TEMP
822// return 0;
823//#else
824// if ( rbearing == SHRT_MIN ) {
825// int ml = 0;
826// int mr = 0;
827// if ( ttf ) {
828// HDC hdc = dc();
829// SelectObject( hdc, hfont );
830// ABC *abc = 0;
831// int n = QT_WA_INLINE( tm.w.tmLastChar - tm.w.tmFirstChar, tm.a.tmLastChar - tm.a.tmFirstChar );
832// if ( n <= max_font_count ) {
833// abc = new ABC[n+1];
834// QT_WA( {
835// GetCharABCWidths(hdc, tm.w.tmFirstChar, tm.w.tmLastChar, abc);
836// }, {
837// GetCharABCWidthsA(hdc,tm.a.tmFirstChar,tm.a.tmLastChar,abc);
838// } );
839// } else {
840// abc = new ABC[char_table_entries+1];
841// QT_WA( {
842// for( int i = 0; i < char_table_entries; i++ )
843// GetCharABCWidths(hdc, char_table[i], char_table[i], abc+i);
844// }, {
845// for( int i = 0; i < char_table_entries; i++ ) {
846// QCString w = QString(QChar(char_table[i])).local8Bit();
847// if ( w.length() == 1 ) {
848// uint ch8 = (uchar)w[0];
849// GetCharABCWidthsA(hdc, ch8, ch8, abc+i );
850// }
851// }
852// } );
853// n = char_table_entries;
854// }
855// ml = abc[0].abcA;
856// mr = abc[0].abcC;
857// for ( int i = 1; i < n; i++ ) {
858// if ( abc[i].abcA + abc[i].abcB + abc[i].abcC != 0 ) {
859// ml = QMIN(ml,abc[i].abcA);
860// mr = QMIN(mr,abc[i].abcC);
861// }
862// }
863// delete [] abc;
864// } else {
865// QT_WA( {
866// ABCFLOAT *abc = 0;
867// int n = tm.w.tmLastChar - tm.w.tmFirstChar+1;
868// if ( n <= max_font_count ) {
869// abc = new ABCFLOAT[n];
870// GetCharABCWidthsFloat(hdc, tm.w.tmFirstChar, tm.w.tmLastChar, abc);
871// } else {
872// abc = new ABCFLOAT[char_table_entries];
873// for( int i = 0; i < char_table_entries; i++ )
874// GetCharABCWidthsFloat(hdc, char_table[i], char_table[i], abc+i);
875// n = char_table_entries;
876// }
877// float fml = abc[0].abcfA;
878// float fmr = abc[0].abcfC;
879// for (int i=1; i<n; i++) {
880// if ( abc[i].abcfA + abc[i].abcfB + abc[i].abcfC != 0 ) {
881// fml = QMIN(fml,abc[i].abcfA);
882// fmr = QMIN(fmr,abc[i].abcfC);
883// }
884// }
885// ml = int(fml-0.9999);
886// mr = int(fmr-0.9999);
887// delete [] abc;
888// } , {
889// ml = 0;
890// mr = -tm.a.tmOverhang;
891// } );
892// }
893// ((QFontEngine *)this)->lbearing = ml;
894// ((QFontEngine *)this)->rbearing = mr;
895// }
896//
897// return rbearing;
898//#endif
899}
900
901//@@TODO (dmik): remove
902//const char *QFontEngineWin::name() const
903//{
904// return 0;
905//}
906
907bool QFontEnginePM::canRender( const QChar *string, int len )
908{
909//@@TODO (dmik): later
910 return TRUE;
911
912// if ( symbol ) {
913// while( len-- ) {
914// if ( getGlyphIndex( cmap, string->unicode() ) == 0 ) {
915// if( string->unicode() < 0x100 ) {
916// if(getGlyphIndex( cmap, string->unicode()+0xf000) == 0)
917// return FALSE;
918// } else {
919// return FALSE;
920// }
921// }
922// string++;
923// }
924// } else if ( ttf ) {
925// while( len-- ) {
926// if ( getGlyphIndex( cmap, string->unicode() ) == 0 )
927// return FALSE;
928// string++;
929// }
930// } else {
931// QT_WA( {
932// while( len-- ) {
933// if ( tm.w.tmFirstChar > string[len].unicode() || tm.w.tmLastChar < string[len].unicode() )
934// return FALSE;
935// }
936// }, {
937// while( len-- ) {
938// if ( tm.a.tmFirstChar > string[len].unicode() || tm.a.tmLastChar < string[len].unicode() )
939// return FALSE;
940// }
941// } );
942// }
943// return TRUE;
944}
945
946QFontEngine::Type QFontEnginePM::type() const
947{
948 return QFontEngine::PM;
949}
950
951
952// ----------------------------------------------------------------------------
953// True type support methods
954// ----------------------------------------------------------------------------
955
956
957
958/// @todo (dmik) need this all?
959//#define MAKE_TAG(ch1, ch2, ch3, ch4) (\
960// (((DWORD)(ch4)) << 24) | \
961// (((DWORD)(ch3)) << 16) | \
962// (((DWORD)(ch2)) << 8) | \
963// ((DWORD)(ch1)) \
964// )
965//
966//static inline Q_UINT32 getUInt(unsigned char *p)
967//{
968// Q_UINT32 val;
969// val = *p++ << 24;
970// val |= *p++ << 16;
971// val |= *p++ << 8;
972// val |= *p;
973//
974// return val;
975//}
976//
977//static inline Q_UINT16 getUShort(unsigned char *p)
978//{
979// Q_UINT16 val;
980// val = *p++ << 8;
981// val |= *p;
982//
983// return val;
984//}
985//
986//static inline void tag_to_string( char *string, Q_UINT32 tag )
987//{
988// string[0] = (tag >> 24)&0xff;
989// string[1] = (tag >> 16)&0xff;
990// string[2] = (tag >> 8)&0xff;
991// string[3] = tag&0xff;
992// string[4] = 0;
993//}
994//
995//static Q_UINT16 getGlyphIndex( unsigned char *table, unsigned short unicode )
996//{
997// unsigned short format = getUShort( table );
998// if ( format == 0 ) {
999// if ( unicode < 256 )
1000// return (int) *(table+6+unicode);
1001// } else if ( format == 2 ) {
1002// qWarning("format 2 encoding table for Unicode, not implemented!");
1003// } else if ( format == 4 ) {
1004// Q_UINT16 segCountX2 = getUShort( table + 6 );
1005// unsigned char *ends = table + 14;
1006// Q_UINT16 endIndex = 0;
1007// int i = 0;
1008// for ( ; i < segCountX2/2 && (endIndex = getUShort( ends + 2*i )) < unicode; i++ );
1009//
1010// unsigned char *idx = ends + segCountX2 + 2 + 2*i;
1011// Q_UINT16 startIndex = getUShort( idx );
1012//
1013// if ( startIndex > unicode )
1014// return 0;
1015//
1016// idx += segCountX2;
1017// Q_INT16 idDelta = (Q_INT16)getUShort( idx );
1018// idx += segCountX2;
1019// Q_UINT16 idRangeoffset_t = (Q_UINT16)getUShort( idx );
1020//
1021// Q_UINT16 glyphIndex;
1022// if ( idRangeoffset_t ) {
1023// Q_UINT16 id = getUShort( idRangeoffset_t + 2*(unicode - startIndex) + idx);
1024// if ( id )
1025// glyphIndex = ( idDelta + id ) % 0x10000;
1026// else
1027// glyphIndex = 0;
1028// } else {
1029// glyphIndex = (idDelta + unicode) % 0x10000;
1030// }
1031// return glyphIndex;
1032// }
1033//
1034// return 0;
1035//}
1036//
1037//
1038//static unsigned char *getCMap( HDC hdc, bool &symbol )
1039//{
1040// const DWORD CMAP = MAKE_TAG( 'c', 'm', 'a', 'p' );
1041//
1042// unsigned char header[4];
1043//
1044// // get the CMAP header and the number of encoding tables
1045// DWORD bytes =
1046//#ifndef Q_OS_TEMP
1047// GetFontData( hdc, CMAP, 0, &header, 4 );
1048//#else
1049// 0;
1050//#endif
1051// if ( bytes == GDI_ERROR )
1052// return 0;
1053// unsigned short version = getUShort( header );
1054// if ( version != 0 )
1055// return 0;
1056//
1057// unsigned short numTables = getUShort( header+2);
1058// unsigned char *maps = new unsigned char[8*numTables];
1059//
1060// // get the encoding table and look for Unicode
1061//#ifndef Q_OS_TEMP
1062// bytes = GetFontData( hdc, CMAP, 4, maps, 8*numTables );
1063//#endif
1064// if ( bytes == GDI_ERROR )
1065// return 0;
1066//
1067// symbol = TRUE;
1068// unsigned int unicode_table = 0;
1069// for ( int n = 0; n < numTables; n++ ) {
1070// Q_UINT32 version = getUInt( maps + 8*n );
1071// // accept both symbol and Unicode encodings. prefer unicode.
1072// if ( version == 0x00030001 || version == 0x00030000 ) {
1073// unicode_table = getUInt( maps + 8*n + 4 );
1074// if ( version == 0x00030001 ) {
1075// symbol = FALSE;
1076// break;
1077// }
1078// }
1079// }
1080//
1081// if ( !unicode_table ) {
1082// // qDebug("no unicode table found" );
1083// return 0;
1084// }
1085//
1086// delete [] maps;
1087//
1088// // get the header of the unicode table
1089//#ifndef Q_OS_TEMP
1090// bytes = GetFontData( hdc, CMAP, unicode_table, &header, 4 );
1091//#endif
1092// if ( bytes == GDI_ERROR )
1093// return 0;
1094//
1095// unsigned short length = getUShort( header+2 );
1096// unsigned char *unicode_data = new unsigned char[length];
1097//
1098// // get the cmap table itself
1099//#ifndef Q_OS_TEMP
1100// bytes = GetFontData( hdc, CMAP, unicode_table, unicode_data, length );
1101//#endif
1102// if ( bytes == GDI_ERROR ) {
1103// delete [] unicode_data;
1104// return 0;
1105// }
1106// return unicode_data;
1107//}
1108
1109
1110
Note: See TracBrowser for help on using the repository browser.