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 30GDISurface::GDISurface(HDC theHDC) 31 : fHdc(theHDC), fCurrentFont(NULL) 32{ 33 // nothing else to do 34} 35 36GDISurface::~GDISurface() 37{ 38 // nothing to do 39} 40 41void GDISurface::setHDC(HDC theHDC) 42{ 43 fHdc = theHDC; 44 fCurrentFont = NULL; 45} 46 47void 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 59void 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 110GDIFontInstance::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 191restore: 192 RestoreDC(hdc, -1); 193} 194 195GDIFontInstance::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 303restore: 304 RestoreDC(hdc, -1); 305} 306 307GDIFontInstance::~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 323LEErrorCode 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 341const void *GDIFontInstance::getFontTable(LETag tableTag) const 342{ 343 return FontTableCache::find(tableTag); 344} 345 346const 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 363void 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 390le_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 409