2 *******************************************************************************
4 * Copyright (C) 1999-2008, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
8 * file name: GDIFontInstance.cpp
10 * created on: 08/09/2000
11 * created by: Eric R. Mader
16 #include "layout/LETypes.h"
17 #include "layout/LESwaps.h"
18 #include "layout/LEFontInstance.h"
20 #include "GDIFontInstance.h"
24 GDISurface::GDISurface(HDC theHDC
)
25 : fHdc(theHDC
), fCurrentFont(NULL
)
30 GDISurface::~GDISurface()
35 void GDISurface::setHDC(HDC theHDC
)
41 void GDISurface::setFont(const GDIFontInstance
*font
)
44 if (fCurrentFont
!= font
) {
46 SelectObject(fHdc
, font
->getFont());
49 SelectObject(fHdc
, font
->getFont());
53 void GDISurface::drawGlyphs(const LEFontInstance
*font
, const LEGlyphID
*glyphs
, le_int32 count
, const float *positions
,
54 le_int32 x
, le_int32 y
, le_int32 width
, le_int32 height
)
56 TTGlyphID
*ttGlyphs
= LE_NEW_ARRAY(TTGlyphID
, count
);
57 le_int32
*dx
= LE_NEW_ARRAY(le_int32
, count
);
58 float *ps
= LE_NEW_ARRAY(float, count
* 2 + 2);
67 for (le_int32 g
= 0; g
< count
; g
+= 1) {
68 TTGlyphID ttGlyph
= (TTGlyphID
) LE_GET_GLYPH(glyphs
[g
]);
70 if (ttGlyph
< 0xFFFE) {
71 ttGlyphs
[out
] = ttGlyph
;
72 dx
[out
] = (le_int32
) (positions
[g
* 2 + 2] - positions
[g
* 2]);
73 ps
[out
* 2] = positions
[g
* 2];
74 ps
[out
* 2 + 1] = positions
[g
* 2 + 1];
79 le_int32 dyStart
, dyEnd
;
81 setFont((GDIFontInstance
*) font
);
86 float yOffset
= ps
[dyStart
* 2 + 1];
87 float xOffset
= ps
[dyStart
* 2];
89 while (dyEnd
< out
&& yOffset
== ps
[dyEnd
* 2 + 1]) {
93 ExtTextOut(fHdc
, x
+ (le_int32
) xOffset
, y
+ (le_int32
) yOffset
- font
->getAscent(), ETO_CLIPPED
| ETO_GLYPH_INDEX
, &clip
,
94 (LPCWSTR
) &ttGlyphs
[dyStart
], dyEnd
- dyStart
, (INT
*) &dx
[dyStart
]);
101 LE_DELETE_ARRAY(ttGlyphs
);
104 GDIFontInstance::GDIFontInstance(GDISurface
*surface
, TCHAR
*faceName
, le_int16 pointSize
, LEErrorCode
&status
)
105 : FontTableCache(), fSurface(surface
), fFont(NULL
),
106 fPointSize(pointSize
), fUnitsPerEM(0), fAscent(0), fDescent(0), fLeading(0),
107 fDeviceScaleX(1), fDeviceScaleY(1), fMapper(NULL
)
112 OUTLINETEXTMETRIC otm
;
113 HDC hdc
= surface
->getHDC();
115 if (LE_FAILURE(status
)) {
121 SetGraphicsMode(hdc
, GM_ADVANCED
);
122 ModifyWorldTransform(hdc
, NULL
, MWT_IDENTITY
);
123 SetViewportOrgEx(hdc
, 0, 0, NULL
);
124 SetWindowOrgEx(hdc
, 0, 0, NULL
);
126 dpiX
= (FLOAT
) GetDeviceCaps(hdc
, LOGPIXELSX
);
127 dpiY
= (FLOAT
) GetDeviceCaps(hdc
, LOGPIXELSY
);
130 pt
.x
= (int) (pointSize
* dpiX
/ 72);
131 pt
.y
= (int) (pointSize
* dpiY
/ 72);
135 pt
.x
= pt
.y
= pointSize
;
138 lf
.lfHeight
= - pt
.y
;
141 lf
.lfOrientation
= 0;
146 lf
.lfCharSet
= DEFAULT_CHARSET
;
147 lf
.lfOutPrecision
= 0;
148 lf
.lfClipPrecision
= 0;
150 lf
.lfPitchAndFamily
= 0;
152 lstrcpy(lf
.lfFaceName
, faceName
);
154 fFont
= CreateFontIndirect(&lf
);
157 status
= LE_FONT_FILE_NOT_FOUND_ERROR
;
161 SelectObject(hdc
, fFont
);
163 UINT ret
= GetOutlineTextMetrics(hdc
, sizeof otm
, &otm
);
166 status
= LE_MISSING_FONT_TABLE_ERROR
;
170 fUnitsPerEM
= otm
.otmEMSquare
;
171 fAscent
= otm
.otmTextMetrics
.tmAscent
;
172 fDescent
= otm
.otmTextMetrics
.tmDescent
;
173 fLeading
= otm
.otmTextMetrics
.tmExternalLeading
;
175 status
= initMapper();
177 if (LE_FAILURE(status
)) {
182 status
= initFontTableCache();
189 GDIFontInstance::GDIFontInstance(GDISurface
*surface
, const char *faceName
, le_int16 pointSize
, LEErrorCode
&status
)
190 : FontTableCache(), fSurface(surface
), fFont(NULL
),
191 fPointSize(pointSize
), fUnitsPerEM(0), fAscent(0), fDescent(0), fLeading(0),
192 fDeviceScaleX(1), fDeviceScaleY(1), fMapper(NULL
)
197 OUTLINETEXTMETRIC otm
;
198 HDC hdc
= surface
->getHDC();
200 if (LE_FAILURE(status
)) {
206 SetGraphicsMode(hdc
, GM_ADVANCED
);
207 ModifyWorldTransform(hdc
, NULL
, MWT_IDENTITY
);
208 SetViewportOrgEx(hdc
, 0, 0, NULL
);
209 SetWindowOrgEx(hdc
, 0, 0, NULL
);
211 dpiX
= (FLOAT
) GetDeviceCaps(hdc
, LOGPIXELSX
);
212 dpiY
= (FLOAT
) GetDeviceCaps(hdc
, LOGPIXELSY
);
214 fDeviceScaleX
= dpiX
/ 72;
215 fDeviceScaleY
= dpiY
/ 72;
218 pt
.x
= (int) (pointSize
* fDeviceScaleX
);
219 pt
.y
= (int) (pointSize
* fDeviceScaleY
);
223 pt
.x
= pt
.y
= pointSize
;
226 lf
.lfHeight
= - pt
.y
;
229 lf
.lfOrientation
= 0;
234 lf
.lfCharSet
= DEFAULT_CHARSET
;
235 lf
.lfOutPrecision
= 0;
236 lf
.lfClipPrecision
= 0;
238 lf
.lfPitchAndFamily
= 0;
240 strcpy(lf
.lfFaceName
, faceName
);
242 fFont
= CreateFontIndirectA(&lf
);
245 status
= LE_FONT_FILE_NOT_FOUND_ERROR
;
249 SelectObject(hdc
, fFont
);
251 UINT ret
= GetOutlineTextMetrics(hdc
, sizeof otm
, &otm
);
254 fUnitsPerEM
= otm
.otmEMSquare
;
255 fAscent
= otm
.otmTextMetrics
.tmAscent
;
256 fDescent
= otm
.otmTextMetrics
.tmDescent
;
257 fLeading
= otm
.otmTextMetrics
.tmExternalLeading
;
259 const HEADTable
*headTable
= NULL
;
260 const HHEATable
*hheaTable
= NULL
;
262 // read unitsPerEm from 'head' table
263 headTable
= (const HEADTable
*) readFontTable(LE_HEAD_TABLE_TAG
);
265 if (headTable
== NULL
) {
266 status
= LE_MISSING_FONT_TABLE_ERROR
;
270 fUnitsPerEM
= SWAPW(headTable
->unitsPerEm
);
271 freeFontTable((const void *)headTable
);
273 hheaTable
= (HHEATable
*) readFontTable(LE_HHEA_TABLE_TAG
);
275 if (hheaTable
== NULL
) {
276 status
= LE_MISSING_FONT_TABLE_ERROR
;
280 fAscent
= (le_int32
) yUnitsToPoints((float) SWAPW(hheaTable
->ascent
));
281 fDescent
= (le_int32
) yUnitsToPoints((float) SWAPW(hheaTable
->descent
));
282 fLeading
= (le_int32
) yUnitsToPoints((float) SWAPW(hheaTable
->lineGap
));
284 freeFontTable((const void *) hheaTable
);
287 status
= initMapper();
289 if (LE_FAILURE(status
)) {
294 status
= initFontTableCache();
301 GDIFontInstance::~GDIFontInstance()
304 flushFontTableCache();
305 delete[] fTableCache
;
309 // FIXME: call RemoveObject first?
317 LEErrorCode
GDIFontInstance::initMapper()
319 LETag cmapTag
= LE_CMAP_TABLE_TAG
;
320 const CMAPTable
*cmap
= (const CMAPTable
*) readFontTable(cmapTag
);
323 return LE_MISSING_FONT_TABLE_ERROR
;
326 fMapper
= CMAPMapper::createUnicodeMapper(cmap
);
328 if (fMapper
== NULL
) {
329 return LE_MISSING_FONT_TABLE_ERROR
;
335 const void *GDIFontInstance::getFontTable(LETag tableTag
) const
337 return FontTableCache::find(tableTag
);
340 const void *GDIFontInstance::readFontTable(LETag tableTag
) const
342 fSurface
->setFont(this);
344 HDC hdc
= fSurface
->getHDC();
345 DWORD stag
= SWAPL(tableTag
);
346 DWORD len
= GetFontData(hdc
, stag
, 0, NULL
, 0);
349 if (len
!= GDI_ERROR
) {
350 result
= LE_NEW_ARRAY(char, len
);
351 GetFontData(hdc
, stag
, 0, result
, len
);
357 void GDIFontInstance::getGlyphAdvance(LEGlyphID glyph
, LEPoint
&advance
) const
362 if (glyph
== 0xFFFE || glyph
== 0xFFFF) {
367 GLYPHMETRICS metrics
;
369 MAT2 identity
= {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
370 HDC hdc
= fSurface
->getHDC();
372 fSurface
->setFont(this);
374 result
= GetGlyphOutline(hdc
, glyph
, GGO_GLYPH_INDEX
| GGO_METRICS
, &metrics
, 0, NULL
, &identity
);
376 if (result
== GDI_ERROR
) {
380 advance
.fX
= metrics
.gmCellIncX
;
384 le_bool
GDIFontInstance::getGlyphPoint(LEGlyphID glyph
, le_int32 pointNumber
, LEPoint
&point
) const
390 result
= fFontInstance
->getGlyphPoint(glyph
, pointNumber
, pt
);
393 point
.fX
= xUnitsToPoints(pt
.fX
);
394 point
.fY
= yUnitsToPoints(pt
.fY
);