Imported Upstream version 58.2
[platform/upstream/icu.git] / source / samples / layout / GDIFontInstance.cpp
1 /*
2  *******************************************************************************
3  *
4  *   Copyright (C) 2016 and later: Unicode, Inc. and others.
5  *   License & terms of use: http://www.unicode.org/copyright.html#License
6  *
7  *******************************************************************************
8  *******************************************************************************
9  *
10  *   Copyright (C) 1999-2008, International Business Machines
11  *   Corporation and others.  All Rights Reserved.
12  *
13  *******************************************************************************
14  *   file name:  GDIFontInstance.cpp
15  *
16  *   created on: 08/09/2000
17  *   created by: Eric R. Mader
18  */
19
20 #include <windows.h>
21
22 #include "layout/LETypes.h"
23 #include "layout/LESwaps.h"
24 #include "layout/LEFontInstance.h"
25
26 #include "GDIFontInstance.h"
27 #include "sfnt.h"
28 #include "cmaps.h"
29
30 GDISurface::GDISurface(HDC theHDC)
31     : fHdc(theHDC), fCurrentFont(NULL)
32 {
33     // nothing else to do
34 }
35
36 GDISurface::~GDISurface()
37 {
38     // nothing to do
39 }
40
41 void GDISurface::setHDC(HDC theHDC)
42 {
43     fHdc         = theHDC;
44     fCurrentFont = NULL;
45 }
46
47 void GDISurface::setFont(const GDIFontInstance *font)
48 {
49 #if 0
50     if (fCurrentFont != font) {
51         fCurrentFont = font;
52         SelectObject(fHdc, font->getFont());
53     }
54 #else
55     SelectObject(fHdc, font->getFont());
56 #endif
57 }
58
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)
61 {
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);
65     le_int32   out = 0;
66     RECT clip;
67
68     clip.top    = 0;
69     clip.left   = 0;
70     clip.bottom = height;
71     clip.right  = width;
72
73     for (le_int32 g = 0; g < count; g += 1) {
74         TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(glyphs[g]);
75
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];
81             out += 1;
82         }
83     }
84
85     le_int32 dyStart, dyEnd;
86
87     setFont((GDIFontInstance *) font);
88
89     dyStart = dyEnd = 0;
90
91     while (dyEnd < out) {
92         float yOffset = ps[dyStart * 2 + 1];
93         float xOffset = ps[dyStart * 2];
94
95         while (dyEnd < out && yOffset == ps[dyEnd * 2 + 1]) {
96             dyEnd += 1;
97         }
98
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]);
101
102         dyStart = dyEnd;
103     }
104
105     LE_DELETE_ARRAY(ps);
106     LE_DELETE_ARRAY(dx);
107     LE_DELETE_ARRAY(ttGlyphs);
108 }
109
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)
114 {
115     LOGFONT lf;
116     FLOAT dpiX, dpiY;
117     POINT pt;
118     OUTLINETEXTMETRIC otm;
119     HDC hdc = surface->getHDC();
120
121     if (LE_FAILURE(status)) {
122         return;
123     }
124
125     SaveDC(hdc);
126
127     SetGraphicsMode(hdc, GM_ADVANCED);
128     ModifyWorldTransform(hdc, NULL, MWT_IDENTITY);
129     SetViewportOrgEx(hdc, 0, 0, NULL);
130     SetWindowOrgEx(hdc, 0, 0, NULL);
131
132     dpiX = (FLOAT) GetDeviceCaps(hdc, LOGPIXELSX);
133     dpiY = (FLOAT) GetDeviceCaps(hdc, LOGPIXELSY);
134
135 #if 1
136     pt.x = (int) (pointSize * dpiX / 72);
137     pt.y = (int) (pointSize * dpiY / 72);
138
139     DPtoLP(hdc, &pt, 1);
140 #else
141     pt.x = pt.y = pointSize;
142 #endif
143
144     lf.lfHeight = - pt.y;
145     lf.lfWidth = 0;
146     lf.lfEscapement = 0;
147     lf.lfOrientation = 0;
148     lf.lfWeight = 0;
149     lf.lfItalic = 0;
150     lf.lfUnderline = 0;
151     lf.lfStrikeOut = 0;
152     lf.lfCharSet = DEFAULT_CHARSET;
153     lf.lfOutPrecision = 0;
154     lf.lfClipPrecision = 0;
155     lf.lfQuality = 0;
156     lf.lfPitchAndFamily = 0;
157
158     lstrcpy(lf.lfFaceName, faceName);
159
160     fFont = CreateFontIndirect(&lf);
161
162     if (fFont == NULL) {
163         status = LE_FONT_FILE_NOT_FOUND_ERROR;
164         return;
165     }
166
167     SelectObject(hdc, fFont);
168
169     UINT ret = GetOutlineTextMetrics(hdc, sizeof otm, &otm);
170
171     if (ret == 0) {
172         status = LE_MISSING_FONT_TABLE_ERROR;
173         goto restore;
174     }
175
176     fUnitsPerEM = otm.otmEMSquare;
177     fAscent  = otm.otmTextMetrics.tmAscent;
178     fDescent = otm.otmTextMetrics.tmDescent;
179     fLeading = otm.otmTextMetrics.tmExternalLeading;
180
181     status = initMapper();
182
183     if (LE_FAILURE(status)) {
184         goto restore;
185     }
186
187 #if 0
188     status = initFontTableCache();
189 #endif
190
191 restore:
192     RestoreDC(hdc, -1);
193 }
194
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)
199 {
200     LOGFONTA lf;
201     FLOAT dpiX, dpiY;
202     POINT pt;
203     OUTLINETEXTMETRIC otm;
204     HDC hdc = surface->getHDC();
205
206     if (LE_FAILURE(status)) {
207         return;
208     }
209
210     SaveDC(hdc);
211
212     SetGraphicsMode(hdc, GM_ADVANCED);
213     ModifyWorldTransform(hdc, NULL, MWT_IDENTITY);
214     SetViewportOrgEx(hdc, 0, 0, NULL);
215     SetWindowOrgEx(hdc, 0, 0, NULL);
216
217     dpiX = (FLOAT) GetDeviceCaps(hdc, LOGPIXELSX);
218     dpiY = (FLOAT) GetDeviceCaps(hdc, LOGPIXELSY);
219
220     fDeviceScaleX = dpiX / 72;
221     fDeviceScaleY = dpiY / 72;
222
223 #if 1
224     pt.x = (int) (pointSize * fDeviceScaleX);
225     pt.y = (int) (pointSize * fDeviceScaleY);
226
227     DPtoLP(hdc, &pt, 1);
228 #else
229     pt.x = pt.y = pointSize;
230 #endif
231
232     lf.lfHeight = - pt.y;
233     lf.lfWidth = 0;
234     lf.lfEscapement = 0;
235     lf.lfOrientation = 0;
236     lf.lfWeight = 0;
237     lf.lfItalic = 0;
238     lf.lfUnderline = 0;
239     lf.lfStrikeOut = 0;
240     lf.lfCharSet = DEFAULT_CHARSET;
241     lf.lfOutPrecision = 0;
242     lf.lfClipPrecision = 0;
243     lf.lfQuality = 0;
244     lf.lfPitchAndFamily = 0;
245
246     strcpy(lf.lfFaceName, faceName);
247
248     fFont = CreateFontIndirectA(&lf);
249
250     if (fFont == NULL) {
251         status = LE_FONT_FILE_NOT_FOUND_ERROR;
252         return;
253     }
254
255     SelectObject(hdc, fFont);
256
257     UINT ret = GetOutlineTextMetrics(hdc, sizeof otm, &otm);
258
259     if (ret != 0) {
260         fUnitsPerEM = otm.otmEMSquare;
261         fAscent  = otm.otmTextMetrics.tmAscent;
262         fDescent = otm.otmTextMetrics.tmDescent;
263         fLeading = otm.otmTextMetrics.tmExternalLeading;
264     } else {
265         const HEADTable *headTable = NULL;
266         const HHEATable *hheaTable = NULL;
267
268         // read unitsPerEm from 'head' table
269         headTable = (const HEADTable *) readFontTable(LE_HEAD_TABLE_TAG);
270
271         if (headTable == NULL) {
272             status = LE_MISSING_FONT_TABLE_ERROR;
273             goto restore;
274         }
275
276         fUnitsPerEM   = SWAPW(headTable->unitsPerEm);
277         freeFontTable((const void *)headTable);
278
279         hheaTable = (HHEATable *) readFontTable(LE_HHEA_TABLE_TAG);
280
281         if (hheaTable == NULL) {
282             status = LE_MISSING_FONT_TABLE_ERROR;
283             goto restore;
284         }
285
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));
289
290         freeFontTable((const void *) hheaTable);
291     }
292
293     status = initMapper();
294
295     if (LE_FAILURE(status)) {
296         goto restore;
297     }
298
299 #if 0
300     status = initFontTableCache();
301 #endif
302
303 restore:
304     RestoreDC(hdc, -1);
305 }
306
307 GDIFontInstance::~GDIFontInstance()
308 {
309 #if 0
310     flushFontTableCache();
311     delete[] fTableCache;
312 #endif
313
314     if (fFont != NULL) {
315         // FIXME: call RemoveObject first?
316         DeleteObject(fFont);
317     }
318
319     delete fMapper;
320     fMapper = NULL;
321 }
322
323 LEErrorCode GDIFontInstance::initMapper()
324 {
325     LETag cmapTag = LE_CMAP_TABLE_TAG;
326     const CMAPTable *cmap = (const CMAPTable *) readFontTable(cmapTag);
327
328     if (cmap == NULL) {
329         return LE_MISSING_FONT_TABLE_ERROR;
330     }
331
332     fMapper = CMAPMapper::createUnicodeMapper(cmap);
333
334     if (fMapper == NULL) {
335         return LE_MISSING_FONT_TABLE_ERROR;
336     }
337
338     return LE_NO_ERROR;
339 }
340
341 const void *GDIFontInstance::getFontTable(LETag tableTag) const
342 {
343     return FontTableCache::find(tableTag);
344 }
345
346 const void *GDIFontInstance::readFontTable(LETag tableTag) const
347 {
348     fSurface->setFont(this);
349
350     HDC   hdc    = fSurface->getHDC();
351     DWORD stag   = SWAPL(tableTag);
352     DWORD len    = GetFontData(hdc, stag, 0, NULL, 0);
353     void *result = NULL;
354
355     if (len != GDI_ERROR) {
356         result = LE_NEW_ARRAY(char, len);
357         GetFontData(hdc, stag, 0, result, len);
358     }
359
360     return result;
361 }
362
363 void GDIFontInstance::getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const
364 {
365     advance.fX = 0;
366     advance.fY = 0;
367
368     if (glyph == 0xFFFE || glyph == 0xFFFF) {
369         return;
370     }
371
372
373     GLYPHMETRICS metrics;
374     DWORD result;
375     MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
376     HDC hdc = fSurface->getHDC();
377
378     fSurface->setFont(this);
379
380     result = GetGlyphOutline(hdc, glyph, GGO_GLYPH_INDEX | GGO_METRICS, &metrics, 0, NULL, &identity);
381
382     if (result == GDI_ERROR) {
383         return;
384     }
385
386     advance.fX = metrics.gmCellIncX;
387     return;
388 }
389
390 le_bool GDIFontInstance::getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) const
391 {
392 #if 0
393     hsFixedPoint2 pt;
394     le_bool result;
395
396     result = fFontInstance->getGlyphPoint(glyph, pointNumber, pt);
397
398     if (result) {
399         point.fX = xUnitsToPoints(pt.fX);
400         point.fY = yUnitsToPoints(pt.fY);
401     }
402
403     return result;
404 #else
405     return FALSE;
406 #endif
407 }
408