FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool oblique, bool useGDI) : m_font(RefCountedGDIHandle<HFONT>::create(font)) , m_size(size) #if PLATFORM(CG) , m_cgFont(0) #elif PLATFORM(CAIRO) , m_fontFace(0) , m_scaledFont(0) #endif , m_syntheticBold(bold) , m_syntheticOblique(oblique) , m_useGDI(useGDI) { HDC hdc = GetDC(0); SaveDC(hdc); SelectObject(hdc, font); UINT bufferSize = GetOutlineTextMetricsW(hdc, 0, NULL); ASSERT_WITH_MESSAGE(bufferSize, "Bitmap fonts not supported with CoreGraphics."); if (bufferSize) { OUTLINETEXTMETRICW* metrics = (OUTLINETEXTMETRICW*)malloc(bufferSize); GetOutlineTextMetricsW(hdc, bufferSize, metrics); WCHAR* faceName = (WCHAR*)((uintptr_t)metrics + (uintptr_t)metrics->otmpFaceName); platformDataInit(font, size, hdc, faceName); free(metrics); } RestoreDC(hdc, -1); ReleaseDC(0, hdc); }
static OUTLINETEXTMETRICW *getOutlineTextMetric(HDC hdc) { int size; size = GetOutlineTextMetricsW(hdc, 0, 0); OUTLINETEXTMETRICW *otm = (OUTLINETEXTMETRICW *)malloc(size); GetOutlineTextMetricsW(hdc, size, otm); return otm; }
static void gdi_get_font_metrics(LOGFONTW *lf, struct font_metrics *fm) { HDC hdc; HFONT hfont; NEWTEXTMETRICW ntm; OUTLINETEXTMETRICW otm; int ret; hdc = CreateCompatibleDC(0); /* it's the only way to get extended NEWTEXTMETRIC fields */ ret = EnumFontFamiliesExW(hdc, lf, font_enum_proc, (LPARAM)&ntm, 0); ok(!ret, "EnumFontFamiliesExW failed to find %s\n", wine_dbgstr_w(lf->lfFaceName)); hfont = CreateFontIndirectW(lf); SelectObject(hdc, hfont); otm.otmSize = sizeof(otm); ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm); ok(ret, "GetOutlineTextMetrics failed\n"); DeleteDC(hdc); DeleteObject(hfont); fm->lfHeight = -otm.otmTextMetrics.tmAscent; fm->line_spacing = ntm.ntmCellHeight; fm->font_size = (REAL)otm.otmTextMetrics.tmAscent; fm->font_height = (REAL)fm->line_spacing * fm->font_size / (REAL)ntm.ntmSizeEM; fm->em_height = ntm.ntmSizeEM; fm->ascent = ntm.ntmSizeEM; fm->descent = ntm.ntmCellHeight - ntm.ntmSizeEM; }
FontPlatformData::FontPlatformData(GDIObject<HFONT> font, float size, bool bold, bool oblique, bool useGDI) : m_font(SharedGDIObject<HFONT>::create(WTFMove(font))) , m_size(size) , m_orientation(Horizontal) , m_widthVariant(RegularWidth) , m_isColorBitmapFont(false) , m_syntheticBold(bold) , m_syntheticOblique(oblique) , m_useGDI(useGDI) { HWndDC hdc(0); SaveDC(hdc); ::SelectObject(hdc, m_font->get()); UINT bufferSize = GetOutlineTextMetrics(hdc, 0, NULL); ASSERT_WITH_MESSAGE(bufferSize, "Bitmap fonts not supported with CoreGraphics."); if (bufferSize) { OUTLINETEXTMETRICW* metrics = (OUTLINETEXTMETRICW*)malloc(bufferSize); GetOutlineTextMetricsW(hdc, bufferSize, metrics); WCHAR* faceName = (WCHAR*)((uintptr_t)metrics + (uintptr_t)metrics->otmpFaceName); platformDataInit(m_font->get(), size, hdc, faceName); free(metrics); } RestoreDC(hdc, -1); }
LONG WINAPI TTGetEmbeddingType(HDC hDC, ULONG *status) { OUTLINETEXTMETRICW otm; TRACE("(%p %p)\n", hDC, status); if (!hDC) return E_HDCINVALID; otm.otmSize = sizeof(otm); if (!GetOutlineTextMetricsW(hDC, otm.otmSize, &otm)) return E_NOTATRUETYPEFONT; if (!status) return E_PERMISSIONSINVALID; if (otm.otmfsType == LICENSE_INSTALLABLE) *status = EMBED_INSTALLABLE; else if (otm.otmfsType & LICENSE_NOEMBEDDING) *status = EMBED_NOEMBEDDING; else if (otm.otmfsType & LICENSE_PREVIEWPRINT) *status = EMBED_PREVIEWPRINT; else if (otm.otmfsType & LICENSE_EDITABLE) *status = EMBED_EDITABLE; return E_NONE; }
static void test_GetMetrics(void) { IDWriteGdiInterop *interop; DWRITE_FONT_METRICS metrics; OUTLINETEXTMETRICW otm; IDWriteFont *font; LOGFONTW logfont; HRESULT hr; HDC hdc; HFONT hfont; int ret; hr = IDWriteFactory_GetGdiInterop(factory, &interop); EXPECT_HR(hr, S_OK); memset(&logfont, 0, sizeof(logfont)); logfont.lfHeight = 12; logfont.lfWidth = 12; logfont.lfWeight = FW_NORMAL; logfont.lfItalic = 1; lstrcpyW(logfont.lfFaceName, tahomaW); hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font); ok(hr == S_OK, "got 0x%08x\n", hr); hfont = CreateFontIndirectW(&logfont); hdc = CreateCompatibleDC(0); SelectObject(hdc, hfont); otm.otmSize = sizeof(otm); ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm); ok(ret, "got %d\n", ret); DeleteDC(hdc); DeleteObject(hfont); if (0) /* crashes on native */ IDWriteFont_GetMetrics(font, NULL); memset(&metrics, 0, sizeof(metrics)); IDWriteFont_GetMetrics(font, &metrics); ok(metrics.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics.designUnitsPerEm); ok(metrics.ascent != 0, "ascent %u\n", metrics.ascent); ok(metrics.descent != 0, "descent %u\n", metrics.descent); todo_wine ok(metrics.lineGap == 0, "lineGap %d\n", metrics.lineGap); ok(metrics.capHeight, "capHeight %u\n", metrics.capHeight); ok(metrics.xHeight != 0, "xHeight %u\n", metrics.xHeight); ok(metrics.underlinePosition < 0, "underlinePosition %d\n", metrics.underlinePosition); ok(metrics.underlineThickness != 0, "underlineThickness %u\n", metrics.underlineThickness); ok(metrics.strikethroughPosition > 0, "strikethroughPosition %d\n", metrics.strikethroughPosition); ok(metrics.strikethroughThickness != 0, "strikethroughThickness %u\n", metrics.strikethroughThickness); IDWriteFont_Release(font); IDWriteGdiInterop_Release(interop); }
/******************************************************************************* * GdipCreateFont [GDIPLUS.@] * * Create a new font based off of a FontFamily * * PARAMS * *fontFamily [I] Family to base the font off of * emSize [I] Size of the font * style [I] Bitwise OR of FontStyle enumeration * unit [I] Unit emSize is measured in * **font [I] the resulting Font object * * RETURNS * SUCCESS: Ok * FAILURE: InvalidParameter if fontfamily or font is NULL. * FAILURE: FontFamilyNotFound if an invalid FontFamily is given * * NOTES * UnitDisplay is unsupported. * emSize is stored separately from lfHeight, to hold the fraction. */ GpStatus WINGDIPAPI GdipCreateFont(GDIPCONST GpFontFamily *fontFamily, REAL emSize, INT style, Unit unit, GpFont **font) { HFONT hfont; OUTLINETEXTMETRICW otm; LOGFONTW lfw; HDC hdc; GpStatus stat; int ret; if (!fontFamily || !font || emSize < 0.0) return InvalidParameter; TRACE("%p (%s), %f, %d, %d, %p\n", fontFamily, debugstr_w(fontFamily->FamilyName), emSize, style, unit, font); memset(&lfw, 0, sizeof(lfw)); stat = GdipGetFamilyName(fontFamily, lfw.lfFaceName, LANG_NEUTRAL); if (stat != Ok) return stat; lfw.lfHeight = -units_to_pixels(emSize, unit, fontFamily->dpi); lfw.lfWeight = style & FontStyleBold ? FW_BOLD : FW_REGULAR; lfw.lfItalic = style & FontStyleItalic; lfw.lfUnderline = style & FontStyleUnderline; lfw.lfStrikeOut = style & FontStyleStrikeout; hfont = CreateFontIndirectW(&lfw); hdc = CreateCompatibleDC(0); SelectObject(hdc, hfont); otm.otmSize = sizeof(otm); ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm); DeleteDC(hdc); DeleteObject(hfont); if (!ret) return NotTrueTypeFont; *font = GdipAlloc(sizeof(GpFont)); if (!*font) return OutOfMemory; (*font)->unit = unit; (*font)->emSize = emSize; (*font)->otm = otm; stat = clone_font_family(fontFamily, &(*font)->family); if (stat != Ok) { GdipFree(*font); return stat; } TRACE("<-- %p\n", *font); return Ok; }
static BOOL get_font_metrics(HDC hdc, struct font_metrics *fm) { OUTLINETEXTMETRICW otm; TT_OS2_V2 tt_os2; TT_HHEA tt_hori; LONG size; UINT16 line_gap; otm.otmSize = sizeof(otm); if (!GetOutlineTextMetricsW(hdc, otm.otmSize, &otm)) return FALSE; fm->em_height = otm.otmEMSquare; fm->dpi = GetDeviceCaps(hdc, LOGPIXELSY); memset(&tt_hori, 0, sizeof(tt_hori)); if (GetFontData(hdc, MS_HHEA_TAG, 0, &tt_hori, sizeof(tt_hori)) != GDI_ERROR) { fm->ascent = GET_BE_WORD(tt_hori.Ascender); fm->descent = -GET_BE_WORD(tt_hori.Descender); TRACE("hhea: ascent %d, descent %d\n", fm->ascent, fm->descent); line_gap = GET_BE_WORD(tt_hori.LineGap); fm->line_spacing = fm->ascent + fm->descent + line_gap; TRACE("line_gap %u, line_spacing %u\n", line_gap, fm->line_spacing); if (fm->ascent + fm->descent != 0) return TRUE; } size = GetFontData(hdc, MS_OS2_TAG, 0, NULL, 0); if (size == GDI_ERROR) return FALSE; if (size > sizeof(tt_os2)) size = sizeof(tt_os2); memset(&tt_os2, 0, sizeof(tt_os2)); if (GetFontData(hdc, MS_OS2_TAG, 0, &tt_os2, size) != size) return FALSE; fm->ascent = GET_BE_WORD(tt_os2.usWinAscent); fm->descent = GET_BE_WORD(tt_os2.usWinDescent); TRACE("usWinAscent %u, usWinDescent %u\n", fm->ascent, fm->descent); if (fm->ascent + fm->descent == 0) { fm->ascent = GET_BE_WORD(tt_os2.sTypoAscender); fm->descent = GET_BE_WORD(tt_os2.sTypoDescender); TRACE("sTypoAscender %u, sTypoDescender %u\n", fm->ascent, fm->descent); } line_gap = GET_BE_WORD(tt_os2.sTypoLineGap); fm->line_spacing = fm->ascent + fm->descent + line_gap; TRACE("line_gap %u, line_spacing %u\n", line_gap, fm->line_spacing); return TRUE; }
/******************************************************************************* * GdipCreateFontFromLogfontW [GDIPLUS.@] */ GpStatus WINGDIPAPI GdipCreateFontFromLogfontW(HDC hdc, GDIPCONST LOGFONTW *logfont, GpFont **font) { HFONT hfont, oldfont; OUTLINETEXTMETRICW otm; GpStatus stat; int ret; TRACE("(%p, %p, %p)\n", hdc, logfont, font); if (!hdc || !logfont || !font) return InvalidParameter; hfont = CreateFontIndirectW(logfont); oldfont = SelectObject(hdc, hfont); otm.otmSize = sizeof(otm); ret = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm); SelectObject(hdc, oldfont); DeleteObject(hfont); if (!ret) return NotTrueTypeFont; *font = GdipAlloc(sizeof(GpFont)); if (!*font) return OutOfMemory; (*font)->unit = UnitWorld; (*font)->emSize = otm.otmTextMetrics.tmAscent; (*font)->otm = otm; stat = GdipCreateFontFamilyFromName(logfont->lfFaceName, NULL, &(*font)->family); if (stat != Ok) { GdipFree(*font); return NotTrueTypeFont; } TRACE("<-- %p\n", *font); return Ok; }
static void test_CreateFontFromLOGFONT(void) { static const WCHAR tahomaspW[] = {'T','a','h','o','m','a',' ',0}; IDWriteGdiInterop *interop; DWRITE_FONT_WEIGHT weight; DWRITE_FONT_STYLE style; IDWriteFont *font; LOGFONTW logfont; LONG weights[][2] = { {FW_NORMAL, DWRITE_FONT_WEIGHT_NORMAL}, {FW_BOLD, DWRITE_FONT_WEIGHT_BOLD}, { 0, DWRITE_FONT_WEIGHT_NORMAL}, { 50, DWRITE_FONT_WEIGHT_NORMAL}, {150, DWRITE_FONT_WEIGHT_NORMAL}, {250, DWRITE_FONT_WEIGHT_NORMAL}, {350, DWRITE_FONT_WEIGHT_NORMAL}, {450, DWRITE_FONT_WEIGHT_NORMAL}, {650, DWRITE_FONT_WEIGHT_BOLD}, {750, DWRITE_FONT_WEIGHT_BOLD}, {850, DWRITE_FONT_WEIGHT_BOLD}, {950, DWRITE_FONT_WEIGHT_BOLD}, {960, DWRITE_FONT_WEIGHT_BOLD}, }; OUTLINETEXTMETRICW otm; HRESULT hr; BOOL ret; HDC hdc; HFONT hfont; int i; UINT r; hr = IDWriteFactory_GetGdiInterop(factory, &interop); EXPECT_HR(hr, S_OK); if (0) /* null out parameter crashes this call */ hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, NULL, NULL); hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, NULL, &font); EXPECT_HR(hr, E_INVALIDARG); memset(&logfont, 0, sizeof(logfont)); logfont.lfHeight = 12; logfont.lfWidth = 12; logfont.lfWeight = FW_NORMAL; logfont.lfItalic = 1; lstrcpyW(logfont.lfFaceName, tahomaW); hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font); EXPECT_HR(hr, S_OK); hfont = CreateFontIndirectW(&logfont); hdc = CreateCompatibleDC(0); SelectObject(hdc, hfont); otm.otmSize = sizeof(otm); r = GetOutlineTextMetricsW(hdc, otm.otmSize, &otm); ok(r, "got %d\n", r); DeleteDC(hdc); DeleteObject(hfont); /* now check properties */ weight = IDWriteFont_GetWeight(font); ok(weight == DWRITE_FONT_WEIGHT_NORMAL, "got %d\n", weight); style = IDWriteFont_GetStyle(font); todo_wine { ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style); ok(otm.otmfsSelection == 1, "got 0x%08x\n", otm.otmfsSelection); } ret = IDWriteFont_IsSymbolFont(font); ok(!ret, "got %d\n", ret); IDWriteFont_Release(font); /* weight values */ for (i = 0; i < sizeof(weights)/(2*sizeof(LONG)); i++) { memset(&logfont, 0, sizeof(logfont)); logfont.lfHeight = 12; logfont.lfWidth = 12; logfont.lfWeight = weights[i][0]; lstrcpyW(logfont.lfFaceName, tahomaW); hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font); EXPECT_HR(hr, S_OK); weight = IDWriteFont_GetWeight(font); ok(weight == weights[i][1], "%d: got %d, expected %d\n", i, weight, weights[i][1]); IDWriteFont_Release(font); } /* weight not from enum */ memset(&logfont, 0, sizeof(logfont)); logfont.lfHeight = 12; logfont.lfWidth = 12; logfont.lfWeight = 550; lstrcpyW(logfont.lfFaceName, tahomaW); hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font); EXPECT_HR(hr, S_OK); weight = IDWriteFont_GetWeight(font); ok(weight == DWRITE_FONT_WEIGHT_NORMAL || broken(weight == DWRITE_FONT_WEIGHT_BOLD) /* win7 w/o SP */, "got %d\n", weight); IDWriteFont_Release(font); /* empty or nonexistent face name */ memset(&logfont, 0, sizeof(logfont)); logfont.lfHeight = 12; logfont.lfWidth = 12; logfont.lfWeight = FW_NORMAL; lstrcpyW(logfont.lfFaceName, blahW); font = (void*)0xdeadbeef; hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font); todo_wine { EXPECT_HR(hr, DWRITE_E_NOFONT); ok(font == NULL, "got %p\n", font); if(font) IDWriteFont_Release(font); } memset(&logfont, 0, sizeof(logfont)); logfont.lfHeight = 12; logfont.lfWidth = 12; logfont.lfWeight = FW_NORMAL; lstrcpyW(logfont.lfFaceName, tahomaspW); font = (void*)0xdeadbeef; hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font); todo_wine { EXPECT_HR(hr, DWRITE_E_NOFONT); ok(font == NULL, "got %p\n", font); if(font) IDWriteFont_Release(font); } memset(&logfont, 0, sizeof(logfont)); logfont.lfHeight = 12; logfont.lfWidth = 12; logfont.lfWeight = FW_NORMAL; font = (void*)0xdeadbeef; hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font); todo_wine { EXPECT_HR(hr, DWRITE_E_NOFONT); ok(font == NULL, "got %p\n", font); if(font) IDWriteFont_Release(font); } IDWriteGdiInterop_Release(interop); }
void tool_fontextract(const vdfastvector<const char *>& args, const vdfastvector<const char *>& switches) { if (args.size() < 6) help_fontextract(); printf("Asuka: Extracting font: %s -> %s.\n", args[0], args[4]); int startChar; int endChar; if (1 != sscanf(args[2], "%d", &startChar) || 1 != sscanf(args[3], "%d", &endChar)) help_fontextract(); if (startChar < 0 || endChar > 0xFFFF || endChar <= startChar) { printf("Asuka: Invalid character range %d-%d\n", startChar, endChar); exit(10); } int fontsAdded = AddFontResourceEx(args[0], FR_NOT_ENUM | FR_PRIVATE, 0); if (!fontsAdded) { printf("Asuka: Unable to load font file: %s\n", args[0]); exit(10); } HFONT hfont = CreateFontA(10, 0, 0, 0, 0, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, args[1]); if (!hfont) { printf("Asuka: Unable to instantiate font: %s\n", args[1]); exit(10); } HDC hdc = CreateDC("DISPLAY", 0, 0, 0); HGDIOBJ hfontOld = SelectObject(hdc, hfont); MAT2 m = { {0,1},{0,0},{0,0},{0,1} }; union { OUTLINETEXTMETRICW m; char buf[2048]; } metrics; if (!GetOutlineTextMetricsW(hdc, sizeof metrics, &metrics.m)) { printf("Asuka: Unable to retrieve outline text metrics.\n"); exit(10); } SelectObject(hdc, hfontOld); DeleteObject(hfont); hfont = CreateFontA(metrics.m.otmEMSquare, 0, 0, 0, 0, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, args[1]); if (!hfont) { printf("Asuka: Unable to instantiate font: %s\n", args[1]); exit(10); } hfontOld = SelectObject(hdc, hfont); if (!GetOutlineTextMetricsW(hdc, sizeof metrics, &metrics.m)) { printf("Asuka: Unable to retrieve outline text metrics.\n"); exit(10); } FILE *f = fopen(args[4], "w"); if (!f) { printf("Asuka: Unable to open output file: %s\n", args[4]); exit(10); } std::vector<GlyphInfo> glyphs(endChar - startChar + 1); sint32 minX = 0x7FFFFFFF; sint32 minY = 0x7FFFFFFF; sint32 maxX = -0x7FFFFFFF - 1; sint32 maxY = -0x7FFFFFFF - 1; vdfastvector<sint32> points; vdfastvector<uint8> commands; for(int c=startChar; c<endChar; ++c) { GlyphInfo& info = glyphs[c - startChar]; info.mPointStart = points.size() >> 1; info.mCommandStart = commands.size(); GetCharABCWidthsFloatW(hdc, c, c, &info.mWidths); // encode glyph outline GLYPHMETRICS gm; if (GDI_ERROR == GetGlyphOutlineW(hdc, c, GGO_METRICS, &gm, 0, NULL, &m)) { printf("Asuka: Unable to obtain glyph metrics for char %d.\n", c); exit(20); } DWORD dwBytes = GetGlyphOutlineW(hdc, c, GGO_NATIVE | GGO_UNHINTED, &gm, 0, NULL, &m); if (dwBytes == 0xFFFFFFFF) { printf("Asuka: Unable to obtain glyph outline for char %d.\n", c); exit(20); } // GetGlyphOutline() doesn't like providing results for spaces. if (gm.gmBlackBoxX <= 0 || gm.gmBlackBoxY <= 0) continue; void *buf = malloc(dwBytes); GetGlyphOutlineW(hdc, c, GGO_NATIVE | GGO_UNHINTED, &gm, dwBytes, buf, &m); void *limit = (char *)buf + dwBytes; TTPOLYGONHEADER *pHdr = (TTPOLYGONHEADER *)buf; sint32 lastCode = 0; while(pHdr != limit) { VDASSERT(pHdr->dwType == TT_POLYGON_TYPE); sint32 x = *(const sint32 *)&pHdr->pfxStart.x; sint32 y = *(const sint32 *)&pHdr->pfxStart.y; if (minX > x) minX = x; if (minY > y) minY = y; if (maxX < x) maxX = x; if (maxY < y) maxY = y; points.push_back(x); points.push_back(y); TTPOLYCURVE *pCurve = (TTPOLYCURVE *)(pHdr + 1); TTPOLYCURVE *pCurveEnd = (TTPOLYCURVE *)((char *)pHdr + pHdr->cb); while(pCurve != pCurveEnd) { VDASSERT(pCurve->wType == TT_PRIM_QSPLINE || pCurve->wType == TT_PRIM_LINE); POINTFX *ppfx = pCurve->apfx; for(int i=0; i<pCurve->cpfx; ++i) { sint32 x = *(const sint32 *)&ppfx->x; sint32 y = *(const sint32 *)&ppfx->y; if (minX > x) minX = x; if (minY > y) minY = y; if (maxX < x) maxX = x; if (maxY < y) maxY = y; points.push_back(x); points.push_back(y); ++ppfx; } if (pCurve->wType == TT_PRIM_LINE) { if ((lastCode & 3) != 2) { if (lastCode) commands.push_back(lastCode); lastCode = 2 - 4; } for(int i=0; i<pCurve->cpfx; ++i) { if (lastCode >= 0x7C) { commands.push_back(lastCode); lastCode = 2 - 4; } lastCode += 4; } } else { VDASSERT(pCurve->wType == TT_PRIM_QSPLINE); VDASSERT(!(pCurve->cpfx % 2)); if ((lastCode & 3) != 3) { if (lastCode) commands.push_back(lastCode); lastCode = 3 - 4; } for(int i=0; i<pCurve->cpfx; i+=2) { if (lastCode >= 0x7C) { commands.push_back(lastCode); lastCode = 3 - 4; } lastCode += 4; } } pCurve = (TTPOLYCURVE *)ppfx; } if (lastCode) { commands.push_back(lastCode | 0x80); lastCode = 0; } vdptrstep(pHdr, pHdr->cb); } free(buf); } GlyphInfo& lastInfo = glyphs.back(); lastInfo.mPointStart = points.size() >> 1; lastInfo.mCommandStart = commands.size(); // write points fprintf(f, "// Created by Asuka from %s. DO NOT EDIT!\n\n", VDFileSplitPath(args[0])); fprintf(f, "const uint16 %s_FontPointArray[]={\n", args[5]); float scaleX = (maxX > minX) ? 1.0f / (maxX - minX) : 0.0f; float scaleY = (maxY > minY) ? 1.0f / (maxY - minY) : 0.0f; int pointElementCount = points.size(); for(int i=0; i<pointElementCount; i+=2) { uint8 x = VDClampedRoundFixedToUint8Fast((float)(points[i+0] - minX) * scaleX); uint8 y = VDClampedRoundFixedToUint8Fast((float)(points[i+1] - minY) * scaleY); uint16 pt = ((uint16)y << 8) + x; fprintf(f, "0x%04x,", pt); if ((i & 30) == 30) putc('\n', f); } if (pointElementCount & 30) putc('\n', f); fprintf(f, "};\n\n"); // write commands fprintf(f, "const uint8 %s_FontCommandArray[]={\n", args[5]); int commandElementCount = commands.size(); for(int i=0; i<commandElementCount; ++i) { fprintf(f, "0x%02x,", commands[i]); if ((i & 15) == 15) putc('\n', f); } if (commandElementCount & 15) putc('\n', f); fprintf(f, "};\n\n"); // glyph data structures fprintf(f, "const VDOutlineFontGlyphInfo %s_FontGlyphArray[]={\n", args[5]); for(int i=startChar; i<=endChar; ++i) { const GlyphInfo& info = glyphs[i - startChar]; fprintf(f, "{ %d, %d, %d, %d, %d },\n", info.mPointStart, info.mCommandStart, VDRoundToInt(info.mWidths.abcfA), VDRoundToInt(info.mWidths.abcfB), VDRoundToInt(info.mWidths.abcfC)); } fprintf(f, "};\n\n"); // top-level data structure fprintf(f, "const VDOutlineFontInfo %s_FontInfo={\n", args[5]); fprintf(f, "\t%s_FontPointArray,\n", args[5]); fprintf(f, "\t%s_FontCommandArray,\n", args[5]); fprintf(f, "\t%s_FontGlyphArray,\n", args[5]); fprintf(f, "\t%d, %d,\n", startChar, endChar); fprintf(f, "\t%d, %d, %d, %d,\t// bounds (16:16)\n", minX, minY, maxX, maxY); fprintf(f, "\t%d,\t// em square\n", metrics.m.otmEMSquare); fprintf(f, "\t%d,\t// ascent\n", metrics.m.otmAscent); fprintf(f, "\t%d,\t// descent\n", metrics.m.otmDescent); fprintf(f, "\t%d,\t// line gap\n", metrics.m.otmLineGap); fprintf(f, "};\n"); printf("Asuka: %d point bytes, %d command bytes, %d glyph info bytes.\n", (int)points.size(), (int)commands.size(), (endChar - startChar + 1) * 10); SelectObject(hdc, hfontOld); DeleteDC(hdc); DeleteObject(hfont); }