2 *******************************************************************************
4 * © 2016 and later: Unicode, Inc. and others.
5 * License & terms of use: http://www.unicode.org/copyright.html#License
7 *******************************************************************************
8 *******************************************************************************
10 * Copyright (C) 1999-2008, International Business Machines
11 * Corporation and others. All Rights Reserved.
13 *******************************************************************************
14 * file name: GDIFontInstance.cpp
16 * created on: 08/09/2000
17 * created by: Eric R. Mader
22 #include "layout/LETypes.h"
23 #include "layout/LESwaps.h"
24 #include "layout/LEFontInstance.h"
26 #include "GDIFontInstance.h"
30 GDISurface::GDISurface(HDC theHDC
)
31 : fHdc(theHDC
), fCurrentFont(NULL
)
36 GDISurface::~GDISurface()
41 void GDISurface::setHDC(HDC theHDC
)
47 void GDISurface::setFont(const GDIFontInstance
*font
)
50 if (fCurrentFont
!= font
) {
52 SelectObject(fHdc
, font
->getFont());
55 SelectObject(fHdc
, font
->getFont());
59 void GDISurface::drawGlyphs(const LEFontInstance
*font
, const LEGlyphID
*glyphs
, le_int32 count
, const float *positions
,
60 le_int32 x
, le_int32 y
, le_int32 width
, le_int32 height
)
62 TTGlyphID
*ttGlyphs
= LE_NEW_ARRAY(TTGlyphID
, count
);
63 le_int32
*dx
= LE_NEW_ARRAY(le_int32
, count
);
64 float *ps
= LE_NEW_ARRAY(float, count
* 2 + 2);
73 for (le_int32 g
= 0; g
< count
; g
+= 1) {
74 TTGlyphID ttGlyph
= (TTGlyphID
) LE_GET_GLYPH(glyphs
[g
]);
76 if (ttGlyph
< 0xFFFE) {
77 ttGlyphs
[out
] = ttGlyph
;
78 dx
[out
] = (le_int32
) (positions
[g
* 2 + 2] - positions
[g
* 2]);
79 ps
[out
* 2] = positions
[g
* 2];
80 ps
[out
* 2 + 1] = positions
[g
* 2 + 1];
85 le_int32 dyStart
, dyEnd
;
87 setFont((GDIFontInstance
*) font
);
92 float yOffset
= ps
[dyStart
* 2 + 1];
93 float xOffset
= ps
[dyStart
* 2];
95 while (dyEnd
< out
&& yOffset
== ps
[dyEnd
* 2 + 1]) {
99 ExtTextOut(fHdc
, x
+ (le_int32
) xOffset
, y
+ (le_int32
) yOffset
- font
->getAscent(), ETO_CLIPPED
| ETO_GLYPH_INDEX
, &clip
,
100 (LPCWSTR
) &ttGlyphs
[dyStart
], dyEnd
- dyStart
, (INT
*) &dx
[dyStart
]);
107 LE_DELETE_ARRAY(ttGlyphs
);
110 GDIFontInstance::GDIFontInstance(GDISurface
*surface
, TCHAR
*faceName
, le_int16 pointSize
, LEErrorCode
&status
)
111 : FontTableCache(), fSurface(surface
), fFont(NULL
),
112 fPointSize(pointSize
), fUnitsPerEM(0), fAscent(0), fDescent(0), fLeading(0),
113 fDeviceScaleX(1), fDeviceScaleY(1), fMapper(NULL
)
118 OUTLINETEXTMETRIC otm
;
119 HDC hdc
= surface
->getHDC();
121 if (LE_FAILURE(status
)) {
127 SetGraphicsMode(hdc
, GM_ADVANCED
);
128 ModifyWorldTransform(hdc
, NULL
, MWT_IDENTITY
);
129 SetViewportOrgEx(hdc
, 0, 0, NULL
);
130 SetWindowOrgEx(hdc
, 0, 0, NULL
);
132 dpiX
= (FLOAT
) GetDeviceCaps(hdc
, LOGPIXELSX
);
133 dpiY
= (FLOAT
) GetDeviceCaps(hdc
, LOGPIXELSY
);
136 pt
.x
= (int) (pointSize
* dpiX
/ 72);
137 pt
.y
= (int) (pointSize
* dpiY
/ 72);
141 pt
.x
= pt
.y
= pointSize
;
144 lf
.lfHeight
= - pt
.y
;
147 lf
.lfOrientation
= 0;
152 lf
.lfCharSet
= DEFAULT_CHARSET
;
153 lf
.lfOutPrecision
= 0;
154 lf
.lfClipPrecision
= 0;
156 lf
.lfPitchAndFamily
= 0;
158 lstrcpy(lf
.lfFaceName
, faceName
);
160 fFont
= CreateFontIndirect(&lf
);
163 status
= LE_FONT_FILE_NOT_FOUND_ERROR
;
167 SelectObject(hdc
, fFont
);
169 UINT ret
= GetOutlineTextMetrics(hdc
, sizeof otm
, &otm
);
172 status
= LE_MISSING_FONT_TABLE_ERROR
;
176 fUnitsPerEM
= otm
.otmEMSquare
;
177 fAscent
= otm
.otmTextMetrics
.tmAscent
;
178 fDescent
= otm
.otmTextMetrics
.tmDescent
;
179 fLeading
= otm
.otmTextMetrics
.tmExternalLeading
;
181 status
= initMapper();
183 if (LE_FAILURE(status
)) {
188 status
= initFontTableCache();
195 GDIFontInstance::GDIFontInstance(GDISurface
*surface
, const char *faceName
, le_int16 pointSize
, LEErrorCode
&status
)
196 : FontTableCache(), fSurface(surface
), fFont(NULL
),
197 fPointSize(pointSize
), fUnitsPerEM(0), fAscent(0), fDescent(0), fLeading(0),
198 fDeviceScaleX(1), fDeviceScaleY(1), fMapper(NULL
)
203 OUTLINETEXTMETRIC otm
;
204 HDC hdc
= surface
->getHDC();
206 if (LE_FAILURE(status
)) {
212 SetGraphicsMode(hdc
, GM_ADVANCED
);
213 ModifyWorldTransform(hdc
, NULL
, MWT_IDENTITY
);
214 SetViewportOrgEx(hdc
, 0, 0, NULL
);
215 SetWindowOrgEx(hdc
, 0, 0, NULL
);
217 dpiX
= (FLOAT
) GetDeviceCaps(hdc
, LOGPIXELSX
);
218 dpiY
= (FLOAT
) GetDeviceCaps(hdc
, LOGPIXELSY
);
220 fDeviceScaleX
= dpiX
/ 72;
221 fDeviceScaleY
= dpiY
/ 72;
224 pt
.x
= (int) (pointSize
* fDeviceScaleX
);
225 pt
.y
= (int) (pointSize
* fDeviceScaleY
);
229 pt
.x
= pt
.y
= pointSize
;
232 lf
.lfHeight
= - pt
.y
;
235 lf
.lfOrientation
= 0;
240 lf
.lfCharSet
= DEFAULT_CHARSET
;
241 lf
.lfOutPrecision
= 0;
242 lf
.lfClipPrecision
= 0;
244 lf
.lfPitchAndFamily
= 0;
246 strcpy(lf
.lfFaceName
, faceName
);
248 fFont
= CreateFontIndirectA(&lf
);
251 status
= LE_FONT_FILE_NOT_FOUND_ERROR
;
255 SelectObject(hdc
, fFont
);
257 UINT ret
= GetOutlineTextMetrics(hdc
, sizeof otm
, &otm
);
260 fUnitsPerEM
= otm
.otmEMSquare
;
261 fAscent
= otm
.otmTextMetrics
.tmAscent
;
262 fDescent
= otm
.otmTextMetrics
.tmDescent
;
263 fLeading
= otm
.otmTextMetrics
.tmExternalLeading
;
265 const HEADTable
*headTable
= NULL
;
266 const HHEATable
*hheaTable
= NULL
;
268 // read unitsPerEm from 'head' table
269 headTable
= (const HEADTable
*) readFontTable(LE_HEAD_TABLE_TAG
);
271 if (headTable
== NULL
) {
272 status
= LE_MISSING_FONT_TABLE_ERROR
;
276 fUnitsPerEM
= SWAPW(headTable
->unitsPerEm
);
277 freeFontTable((const void *)headTable
);
279 hheaTable
= (HHEATable
*) readFontTable(LE_HHEA_TABLE_TAG
);
281 if (hheaTable
== NULL
) {
282 status
= LE_MISSING_FONT_TABLE_ERROR
;
286 fAscent
= (le_int32
) yUnitsToPoints((float) SWAPW(hheaTable
->ascent
));
287 fDescent
= (le_int32
) yUnitsToPoints((float) SWAPW(hheaTable
->descent
));
288 fLeading
= (le_int32
) yUnitsToPoints((float) SWAPW(hheaTable
->lineGap
));
290 freeFontTable((const void *) hheaTable
);
293 status
= initMapper();
295 if (LE_FAILURE(status
)) {
300 status
= initFontTableCache();
307 GDIFontInstance::~GDIFontInstance()
310 flushFontTableCache();
311 delete[] fTableCache
;
315 // FIXME: call RemoveObject first?
323 LEErrorCode
GDIFontInstance::initMapper()
325 LETag cmapTag
= LE_CMAP_TABLE_TAG
;
326 const CMAPTable
*cmap
= (const CMAPTable
*) readFontTable(cmapTag
);
329 return LE_MISSING_FONT_TABLE_ERROR
;
332 fMapper
= CMAPMapper::createUnicodeMapper(cmap
);
334 if (fMapper
== NULL
) {
335 return LE_MISSING_FONT_TABLE_ERROR
;
341 const void *GDIFontInstance::getFontTable(LETag tableTag
) const
343 return FontTableCache::find(tableTag
);
346 const void *GDIFontInstance::readFontTable(LETag tableTag
) const
348 fSurface
->setFont(this);
350 HDC hdc
= fSurface
->getHDC();
351 DWORD stag
= SWAPL(tableTag
);
352 DWORD len
= GetFontData(hdc
, stag
, 0, NULL
, 0);
355 if (len
!= GDI_ERROR
) {
356 result
= LE_NEW_ARRAY(char, len
);
357 GetFontData(hdc
, stag
, 0, result
, len
);
363 void GDIFontInstance::getGlyphAdvance(LEGlyphID glyph
, LEPoint
&advance
) const
368 if (glyph
== 0xFFFE || glyph
== 0xFFFF) {
373 GLYPHMETRICS metrics
;
375 MAT2 identity
= {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
376 HDC hdc
= fSurface
->getHDC();
378 fSurface
->setFont(this);
380 result
= GetGlyphOutline(hdc
, glyph
, GGO_GLYPH_INDEX
| GGO_METRICS
, &metrics
, 0, NULL
, &identity
);
382 if (result
== GDI_ERROR
) {
386 advance
.fX
= metrics
.gmCellIncX
;
390 le_bool
GDIFontInstance::getGlyphPoint(LEGlyphID glyph
, le_int32 pointNumber
, LEPoint
&point
) const
396 result
= fFontInstance
->getGlyphPoint(glyph
, pointNumber
, pt
);
399 point
.fX
= xUnitsToPoints(pt
.fX
);
400 point
.fY
= yUnitsToPoints(pt
.fY
);