void loadFont() { SetMapperFlags (dc, 0); SetMapMode (dc, MM_TEXT); LOGFONTW lf = { 0 }; lf.lfCharSet = DEFAULT_CHARSET; lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; lf.lfOutPrecision = OUT_OUTLINE_PRECIS; lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; lf.lfQuality = PROOF_QUALITY; lf.lfItalic = (BYTE) (style == "Italic" ? TRUE : FALSE); lf.lfWeight = style == "Bold" ? FW_BOLD : FW_NORMAL; lf.lfHeight = -256; family.copyToUTF16 (lf.lfFaceName, sizeof (lf.lfFaceName)); HFONT standardSizedFont = CreateFontIndirect (&lf); if (standardSizedFont != 0) { if ((previousFontH = SelectObject (dc, standardSizedFont)) != 0) { fontH = standardSizedFont; OUTLINETEXTMETRIC otm; if (GetOutlineTextMetrics (dc, sizeof (otm), &otm) != 0) { lf.lfHeight = -(int) otm.otmEMSquare; fontH = CreateFontIndirect (&lf); SelectObject (dc, fontH); DeleteObject (standardSizedFont); } } } }
//============================================================================== HDC loadFont (const String& fontName_, const bool bold_, const bool italic_, const int size_) { if (fontName != fontName_ || bold != bold_ || italic != italic_ || size != size_) { fontName = fontName_; bold = bold_; italic = italic_; size = size_; if (dc != 0) { DeleteDC (dc); DeleteObject (fontH); kps.free(); } fontH = 0; dc = CreateCompatibleDC (0); SetMapperFlags (dc, 0); SetMapMode (dc, MM_TEXT); LOGFONTW lfw; zerostruct (lfw); lfw.lfCharSet = DEFAULT_CHARSET; lfw.lfClipPrecision = CLIP_DEFAULT_PRECIS; lfw.lfOutPrecision = OUT_OUTLINE_PRECIS; lfw.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; lfw.lfQuality = PROOF_QUALITY; lfw.lfItalic = (BYTE) (italic ? TRUE : FALSE); lfw.lfWeight = bold ? FW_BOLD : FW_NORMAL; fontName.copyToUnicode (lfw.lfFaceName, LF_FACESIZE - 1); lfw.lfHeight = size > 0 ? size : -256; HFONT standardSizedFont = CreateFontIndirect (&lfw); if (standardSizedFont != 0) { if (SelectObject (dc, standardSizedFont) != 0) { fontH = standardSizedFont; if (size == 0) { OUTLINETEXTMETRIC otm; if (GetOutlineTextMetrics (dc, sizeof (otm), &otm) != 0) { lfw.lfHeight = -(int) otm.otmEMSquare; fontH = CreateFontIndirect (&lfw); SelectObject (dc, fontH); DeleteObject (standardSizedFont); } } } else { jassertfalse; } } else { jassertfalse; } } return dc; }
void gfxGDIFont::Initialize() { NS_ASSERTION(!mMetrics, "re-creating metrics? this will leak"); LOGFONTW logFont; // Figure out if we want to do synthetic oblique styling. GDIFontEntry* fe = static_cast<GDIFontEntry*>(GetFontEntry()); bool wantFakeItalic = (mStyle.style & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) && !fe->IsItalic(); // If the font's family has an actual italic face (but font matching // didn't choose it), we have to use a cairo transform instead of asking // GDI to italicize, because that would use a different face and result // in a possible glyph ID mismatch between shaping and rendering. // // We use the mFamilyHasItalicFace flag in the entry in case of user fonts, // where the *CSS* family may not know about italic faces that are present // in the *GDI* family, and which GDI would use if we asked it to perform // the "italicization". bool useCairoFakeItalic = wantFakeItalic && fe->mFamilyHasItalicFace; if (mAdjustedSize == 0.0) { mAdjustedSize = mStyle.size; if (mStyle.sizeAdjust != 0.0 && mAdjustedSize > 0.0) { // to implement font-size-adjust, we first create the "unadjusted" font FillLogFont(logFont, mAdjustedSize, wantFakeItalic && !useCairoFakeItalic); mFont = ::CreateFontIndirectW(&logFont); // initialize its metrics so we can calculate size adjustment Initialize(); // calculate the properly adjusted size, and then proceed // to recreate mFont and recalculate metrics gfxFloat aspect = mMetrics->xHeight / mMetrics->emHeight; mAdjustedSize = mStyle.GetAdjustedSize(aspect); // delete the temporary font and metrics ::DeleteObject(mFont); mFont = nullptr; delete mMetrics; mMetrics = nullptr; } } // (bug 724231) for local user fonts, we don't use GDI's synthetic bold, // as it could lead to a different, incompatible face being used // but instead do our own multi-striking if (mNeedsBold && GetFontEntry()->IsLocalUserFont()) { mApplySyntheticBold = true; } // this may end up being zero mAdjustedSize = ROUND(mAdjustedSize); FillLogFont(logFont, mAdjustedSize, wantFakeItalic && !useCairoFakeItalic); mFont = ::CreateFontIndirectW(&logFont); mMetrics = new gfxFont::Metrics; ::memset(mMetrics, 0, sizeof(*mMetrics)); AutoDC dc; SetGraphicsMode(dc.GetDC(), GM_ADVANCED); AutoSelectFont selectFont(dc.GetDC(), mFont); // Get font metrics if size > 0 if (mAdjustedSize > 0.0) { OUTLINETEXTMETRIC oMetrics; TEXTMETRIC& metrics = oMetrics.otmTextMetrics; if (0 < GetOutlineTextMetrics(dc.GetDC(), sizeof(oMetrics), &oMetrics)) { mMetrics->superscriptOffset = (double)oMetrics.otmptSuperscriptOffset.y; // Some fonts have wrong sign on their subscript offset, bug 410917. mMetrics->subscriptOffset = fabs((double)oMetrics.otmptSubscriptOffset.y); mMetrics->strikeoutSize = (double)oMetrics.otmsStrikeoutSize; mMetrics->strikeoutOffset = (double)oMetrics.otmsStrikeoutPosition; mMetrics->underlineSize = (double)oMetrics.otmsUnderscoreSize; mMetrics->underlineOffset = (double)oMetrics.otmsUnderscorePosition; const MAT2 kIdentityMatrix = { {0, 1}, {0, 0}, {0, 0}, {0, 1} }; GLYPHMETRICS gm; DWORD len = GetGlyphOutlineW(dc.GetDC(), PRUnichar('x'), GGO_METRICS, &gm, 0, nullptr, &kIdentityMatrix); if (len == GDI_ERROR || gm.gmptGlyphOrigin.y <= 0) { // 56% of ascent, best guess for true type mMetrics->xHeight = ROUND((double)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR); } else { mMetrics->xHeight = gm.gmptGlyphOrigin.y; } mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading; gfxFloat typEmHeight = (double)oMetrics.otmAscent - (double)oMetrics.otmDescent; mMetrics->emAscent = ROUND(mMetrics->emHeight * (double)oMetrics.otmAscent / typEmHeight); mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent; if (oMetrics.otmEMSquare > 0) { mFUnitsConvFactor = float(mAdjustedSize / oMetrics.otmEMSquare); } } else { // Make a best-effort guess at extended metrics // this is based on general typographic guidelines // GetTextMetrics can fail if the font file has been removed // or corrupted recently. BOOL result = GetTextMetrics(dc.GetDC(), &metrics); if (!result) { NS_WARNING("Missing or corrupt font data, fasten your seatbelt"); mIsValid = false; memset(mMetrics, 0, sizeof(*mMetrics)); return; } mMetrics->xHeight = ROUND((float)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR); mMetrics->superscriptOffset = mMetrics->xHeight; mMetrics->subscriptOffset = mMetrics->xHeight; mMetrics->strikeoutSize = 1; mMetrics->strikeoutOffset = ROUND(mMetrics->xHeight * 0.5f); // 50% of xHeight mMetrics->underlineSize = 1; mMetrics->underlineOffset = -ROUND((float)metrics.tmDescent * 0.30f); // 30% of descent mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading; mMetrics->emAscent = metrics.tmAscent - metrics.tmInternalLeading; mMetrics->emDescent = metrics.tmDescent; } mMetrics->internalLeading = metrics.tmInternalLeading; mMetrics->externalLeading = metrics.tmExternalLeading; mMetrics->maxHeight = metrics.tmHeight; mMetrics->maxAscent = metrics.tmAscent; mMetrics->maxDescent = metrics.tmDescent; mMetrics->maxAdvance = metrics.tmMaxCharWidth; mMetrics->aveCharWidth = NS_MAX<gfxFloat>(1, metrics.tmAveCharWidth); // The font is monospace when TMPF_FIXED_PITCH is *not* set! // See http://msdn2.microsoft.com/en-us/library/ms534202(VS.85).aspx if (!(metrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) { mMetrics->maxAdvance = mMetrics->aveCharWidth; } // Cache the width of a single space. SIZE size; GetTextExtentPoint32W(dc.GetDC(), L" ", 1, &size); mMetrics->spaceWidth = ROUND(size.cx); // Cache the width of digit zero. // XXX MSDN (http://msdn.microsoft.com/en-us/library/ms534223.aspx) // does not say what the failure modes for GetTextExtentPoint32 are - // is it safe to assume it will fail iff the font has no '0'? if (GetTextExtentPoint32W(dc.GetDC(), L"0", 1, &size)) { mMetrics->zeroOrAveCharWidth = ROUND(size.cx); } else { mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth; } mSpaceGlyph = 0; if (metrics.tmPitchAndFamily & TMPF_TRUETYPE) { WORD glyph; DWORD ret = GetGlyphIndicesW(dc.GetDC(), L" ", 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS); if (ret != GDI_ERROR && glyph != 0xFFFF) { mSpaceGlyph = glyph; } } SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont); } if (IsSyntheticBold()) { mMetrics->aveCharWidth += GetSyntheticBoldOffset(); mMetrics->maxAdvance += GetSyntheticBoldOffset(); } mFontFace = cairo_win32_font_face_create_for_logfontw_hfont(&logFont, mFont); cairo_matrix_t sizeMatrix, ctm; cairo_matrix_init_identity(&ctm); cairo_matrix_init_scale(&sizeMatrix, mAdjustedSize, mAdjustedSize); if (useCairoFakeItalic) { // Skew the matrix to do fake italic if it wasn't already applied // via the LOGFONT double skewfactor = OBLIQUE_SKEW_FACTOR; cairo_matrix_t style; cairo_matrix_init(&style, 1, //xx 0, //yx -1 * skewfactor, //xy 1, //yy 0, //x0 0); //y0 cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style); } cairo_font_options_t *fontOptions = cairo_font_options_create(); if (mAntialiasOption != kAntialiasDefault) { cairo_font_options_set_antialias(fontOptions, GetCairoAntialiasOption(mAntialiasOption)); } mScaledFont = cairo_scaled_font_create(mFontFace, &sizeMatrix, &ctm, fontOptions); cairo_font_options_destroy(fontOptions); if (!mScaledFont || cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) { #ifdef DEBUG char warnBuf[1024]; sprintf(warnBuf, "Failed to create scaled font: %s status: %d", NS_ConvertUTF16toUTF8(mFontEntry->Name()).get(), mScaledFont ? cairo_scaled_font_status(mScaledFont) : 0); NS_WARNING(warnBuf); #endif mIsValid = false; } else { mIsValid = true; } #if 0 printf("Font: %p (%s) size: %f adjusted size: %f valid: %s\n", this, NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size, mAdjustedSize, (mIsValid ? "yes" : "no")); printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent); printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance); printf(" internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading); printf(" spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics->spaceWidth, mMetrics->aveCharWidth, mMetrics->xHeight); printf(" uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n", mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize, mMetrics->superscriptOffset, mMetrics->subscriptOffset); #endif }
//************************************************************************* // DoPaint -- this is the WM_PAINT action routine for the main window. // It places the TrueType logo in the upper left corner of the window, draws // a "fan hub" around it, and draws "fan leaves" of text out from the hub. // These leaves are scaled to reach the bottom and the right edge of the // window, by defining an ellipse centered on the TrueType logo which just // touches those two edges. The text strings span the distance from the // hub to the ellipse along radial lines, and are both scaled and rotated. // Depending on user-set state variables, the ellipse and baselines // for the text fan may be shown (ShowAlignmentMarks), and/or the text may // be shadowed (ShadowAll). Other attributes, such as bolding or // italicization, may be selected from the font dialog box. //************************************************************************* void DoPaint() { PAINTSTRUCT PaintInfo; HDC hDC; LOGFONT FontRec; OUTLINETEXTMETRIC FontMetric; int FontHeight, x, y, j, k; WORD BaseWidth, DesiredExtent, FanTextLen; float Theta; LPCSTR P; RECT R; long TE; int d; BeginPaint(hwnd, &PaintInfo); hDC = PaintInfo.hdc; P = ArcText; FanTextLen = strlen(FanText); // save device context; easiest way to preserve current state SaveDC(hDC); // set initial font data (for TrueType logo) FontRec = CornerFontRec; SetBkMode(hDC, TRANSPARENT); SetTextColor(hDC, RGB(128,128,128)); FontRec.lfHeight = FontRec.lfHeight * 2; FontRec.lfWidth = floor(FontRec.lfWidth * 2.1); // create the TrueType logo SelectObject(hDC, CreateFontIndirect(&FontRec)); TextOut(hDC, 18, 5, "T", 1); SetTextColor(hDC, RGB(0,0,0)); TextOut(hDC, 32, 13,"T", 1); // determine window dimensions & set up fan text parameters GetClientRect(hwnd, &R); FontRec = MainFontRec; DeleteObject(SelectObject(hDC, CreateFontIndirect(&FontRec))); GetOutlineTextMetrics(hDC, sizeof(FontMetric), &FontMetric); FontHeight = FontMetric.otmTextMetrics.tmHeight; SetViewportOrg(hDC, FontHeight+2, 0); R.right -= FontHeight+2; BaseWidth = LOWORD(GetTextExtent(hDC, FanText, FanTextLen)); // get a "black brush" for drawing operations SelectObject(hDC, GetStockObject(NULL_BRUSH)); // if we want to show the alignment marks, draw the bounding ellipse if (ShowAlignmentMarks) { Ellipse(hDC, -R.right, -R.bottom, R.right, R.bottom); } // draw the "hub" of the fan Ellipse(hDC, -(Radius-5), -(Radius-5), (Radius-5), Radius-5); Ellipse(hDC, -(Radius-10), -(Radius-10), (Radius-10), Radius-10); SetTextColor(hDC, FanColor[0]); // loop over the "fan leaves" for ( d = 27; d <= 36; d++) { x = ROUND(Radius * cos(d * Deg2Rad)); y = ROUND(Radius * sin(-d * Deg2Rad)); // -d because y axis is inverted Theta = -d * Deg2Rad; if (x) { Theta = atan((R.right / (R.bottom * 1.0)) * (y / (x * 1.0))); } j = ROUND(R.right * cos(Theta)); k = ROUND(R.bottom * sin(Theta)); if (ShowAlignmentMarks) { MoveTo(hDC, x,y); LineTo(hDC, j,k); } DesiredExtent = ROUND(sqrt(SQR(x*1.0 - j) + SQR(y*1.0 - k))) - 5; FontRec = MainFontRec; FontRec.lfEscapement = d * 100; FontRec.lfWidth = floor((FontMetric.otmTextMetrics.tmAveCharWidth) * (DesiredExtent / (BaseWidth * 1.0))); DeleteObject(SelectObject(hDC, CreateFontIndirect(&FontRec))); TE = GetTextExtent(hDC, FanText, FanTextLen); for ( ;(LOWORD(TE) > DesiredExtent) && (FontRec.lfWidth); FontRec.lfWidth-- ) { // Shave off some character width until the string fits DeleteObject(SelectObject(hDC, CreateFontIndirect(&FontRec))); TE = GetTextExtent(hDC, FanText, FanTextLen); } // Expand the string if necessary to make it fit the desired extent if (LOWORD(TE) < DesiredExtent) { SetTextJustification(hDC,DesiredExtent - LOWORD(TE), 3); } if (ShadowAll) { SetTextColor(hDC, RGB(0,0,0)); TextOut(hDC, x+2, y+1, FanText, FanTextLen); } SetTextColor(hDC, FanColor[d - 27]); TextOut(hDC, x, y, FanText, FanTextLen); // clear justifier's internal error accumulator SetTextJustification(hDC,0,0); if (P[0]) { FontRec = CornerFontRec; FontRec.lfEscapement = (d+10) * 100; FontRec.lfWidth = 0; DeleteObject(SelectObject(hDC, CreateFontIndirect(&FontRec))); SetTextColor(hDC, 0); x = floor((Radius - FontHeight - 5) * cos(d * Deg2Rad)); y = floor((Radius - FontHeight - 5) * sin(-d * Deg2Rad)); TextOut(hDC, x, y, P, 1); P++; } // if } // for d // lose the fan font, selecting in the Borland text font DeleteObject(SelectObject(hDC, CreateFontIndirect(&BorlandFontRec))); TE = GetTextExtent(hDC, BorlandText, strlen(BorlandText)); SetTextColor(hDC, RGB(0,0,0)); // write the Borland text in the lower right corner, with a shadow effect TextOut(hDC, R.right - LOWORD(TE), R.bottom - HIWORD(TE), BorlandText, strlen(BorlandText)); SetTextColor(hDC, RGB(255,0,0)); TextOut(hDC, R.right - LOWORD(TE) - 5, R.bottom - HIWORD(TE), BorlandText, strlen(BorlandText)); DeleteObject(SelectObject(hDC, GetStockObject(SYSTEM_FONT))); // restore the saved DC; easiest way to reset to entry state RestoreDC(hDC, -1); EndPaint(hwnd, &PaintInfo); } // end of DoPaint()
void gfxGDIFont::Initialize() { NS_ASSERTION(!mMetrics, "re-creating metrics? this will leak"); LOGFONTW logFont; if (mAdjustedSize == 0.0) { mAdjustedSize = mStyle.size; if (mStyle.sizeAdjust != 0.0 && mAdjustedSize > 0.0) { // to implement font-size-adjust, we first create the "unadjusted" font FillLogFont(logFont, mAdjustedSize); mFont = ::CreateFontIndirectW(&logFont); // initialize its metrics so we can calculate size adjustment Initialize(); // calculate the properly adjusted size, and then proceed // to recreate mFont and recalculate metrics gfxFloat aspect = mMetrics->xHeight / mMetrics->emHeight; mAdjustedSize = mStyle.GetAdjustedSize(aspect); // delete the temporary font and metrics ::DeleteObject(mFont); mFont = nsnull; delete mMetrics; mMetrics = nsnull; } } FillLogFont(logFont, mAdjustedSize); mFont = ::CreateFontIndirectW(&logFont); mMetrics = new gfxFont::Metrics; ::memset(mMetrics, 0, sizeof(*mMetrics)); AutoDC dc; SetGraphicsMode(dc.GetDC(), GM_ADVANCED); AutoSelectFont selectFont(dc.GetDC(), mFont); // Get font metrics OUTLINETEXTMETRIC oMetrics; TEXTMETRIC& metrics = oMetrics.otmTextMetrics; if (0 < GetOutlineTextMetrics(dc.GetDC(), sizeof(oMetrics), &oMetrics)) { mMetrics->superscriptOffset = (double)oMetrics.otmptSuperscriptOffset.y; // Some fonts have wrong sign on their subscript offset, bug 410917. mMetrics->subscriptOffset = fabs((double)oMetrics.otmptSubscriptOffset.y); mMetrics->strikeoutSize = (double)oMetrics.otmsStrikeoutSize; mMetrics->strikeoutOffset = (double)oMetrics.otmsStrikeoutPosition; mMetrics->underlineSize = (double)oMetrics.otmsUnderscoreSize; mMetrics->underlineOffset = (double)oMetrics.otmsUnderscorePosition; const MAT2 kIdentityMatrix = { {0, 1}, {0, 0}, {0, 0}, {0, 1} }; GLYPHMETRICS gm; DWORD len = GetGlyphOutlineW(dc.GetDC(), PRUnichar('x'), GGO_METRICS, &gm, 0, nsnull, &kIdentityMatrix); if (len == GDI_ERROR || gm.gmptGlyphOrigin.y <= 0) { // 56% of ascent, best guess for true type mMetrics->xHeight = ROUND((double)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR); } else { mMetrics->xHeight = gm.gmptGlyphOrigin.y; } mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading; gfxFloat typEmHeight = (double)oMetrics.otmAscent - (double)oMetrics.otmDescent; mMetrics->emAscent = ROUND(mMetrics->emHeight * (double)oMetrics.otmAscent / typEmHeight); mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent; if (oMetrics.otmEMSquare > 0) { mFUnitsConvFactor = float(GetAdjustedSize() / oMetrics.otmEMSquare); } } else { // Make a best-effort guess at extended metrics // this is based on general typographic guidelines // GetTextMetrics can fail if the font file has been removed // or corrupted recently. BOOL result = GetTextMetrics(dc.GetDC(), &metrics); if (!result) { NS_WARNING("Missing or corrupt font data, fasten your seatbelt"); mIsValid = PR_FALSE; memset(mMetrics, 0, sizeof(*mMetrics)); return; } mMetrics->xHeight = ROUND((float)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR); mMetrics->superscriptOffset = mMetrics->xHeight; mMetrics->subscriptOffset = mMetrics->xHeight; mMetrics->strikeoutSize = 1; mMetrics->strikeoutOffset = ROUND(mMetrics->xHeight * 0.5f); // 50% of xHeight mMetrics->underlineSize = 1; mMetrics->underlineOffset = -ROUND((float)metrics.tmDescent * 0.30f); // 30% of descent mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading; mMetrics->emAscent = metrics.tmAscent - metrics.tmInternalLeading; mMetrics->emDescent = metrics.tmDescent; } mMetrics->internalLeading = metrics.tmInternalLeading; mMetrics->externalLeading = metrics.tmExternalLeading; mMetrics->maxHeight = metrics.tmHeight; mMetrics->maxAscent = metrics.tmAscent; mMetrics->maxDescent = metrics.tmDescent; mMetrics->maxAdvance = metrics.tmMaxCharWidth; mMetrics->aveCharWidth = PR_MAX(1, metrics.tmAveCharWidth); // The font is monospace when TMPF_FIXED_PITCH is *not* set! // See http://msdn2.microsoft.com/en-us/library/ms534202(VS.85).aspx if (!(metrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) { mMetrics->maxAdvance = mMetrics->aveCharWidth; } // Cache the width of a single space. SIZE size; GetTextExtentPoint32W(dc.GetDC(), L" ", 1, &size); mMetrics->spaceWidth = ROUND(size.cx); // Cache the width of digit zero. // XXX MSDN (http://msdn.microsoft.com/en-us/library/ms534223.aspx) // does not say what the failure modes for GetTextExtentPoint32 are - // is it safe to assume it will fail iff the font has no '0'? if (GetTextExtentPoint32W(dc.GetDC(), L"0", 1, &size)) { mMetrics->zeroOrAveCharWidth = ROUND(size.cx); } else { mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth; } mSpaceGlyph = 0; if (metrics.tmPitchAndFamily & TMPF_TRUETYPE) { WORD glyph; DWORD ret = GetGlyphIndicesW(dc.GetDC(), L" ", 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS); if (ret != GDI_ERROR && glyph != 0xFFFF) { mSpaceGlyph = glyph; } } SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont); mFontFace = cairo_win32_font_face_create_for_logfontw_hfont(&logFont, mFont); cairo_matrix_t sizeMatrix, ctm; cairo_matrix_init_identity(&ctm); cairo_matrix_init_scale(&sizeMatrix, mAdjustedSize, mAdjustedSize); cairo_font_options_t *fontOptions = cairo_font_options_create(); if (mAntialiasOption != kAntialiasDefault) { cairo_font_options_set_antialias(fontOptions, GetCairoAntialiasOption(mAntialiasOption)); } mScaledFont = cairo_scaled_font_create(mFontFace, &sizeMatrix, &ctm, fontOptions); cairo_font_options_destroy(fontOptions); if (!mScaledFont || cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) { #ifdef DEBUG char warnBuf[1024]; sprintf(warnBuf, "Failed to create scaled font: %s status: %d", NS_ConvertUTF16toUTF8(mFontEntry->Name()).get(), mScaledFont ? cairo_scaled_font_status(mScaledFont) : 0); NS_WARNING(warnBuf); #endif } mIsValid = PR_TRUE; #if 0 printf("Font: %p (%s) size: %f\n", this, NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size); printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent); printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics.maxAscent, mMetrics.maxDescent, mMetrics.maxAdvance); printf(" internalLeading: %f externalLeading: %f\n", mMetrics.internalLeading, mMetrics.externalLeading); printf(" spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight); printf(" uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize, mMetrics.superscriptOffset, mMetrics.subscriptOffset); #endif }
//�������������������������������������������������������������������������Ŀ // capture_tt � // � // Captures a TrueType font into the output IFF (already open by main) � //��������������������������������������������������������������������������� void capture_tt(char *name, char *ttname, ushort width, ushort height, byte startc, ushort numc) { int j; byte *font, *fptr; ulong fontSize; GBergFileFontHDR header; byte work[4096]; assert(name != 0 && ttname != 0 && height > 0); memset(&header,0,sizeof(header)); strncpy(header.name,name,sizeof(header.name)); if (((int)startc+(int)numc-1) > 256) { cout << "��� Error: number of characters in set must fit in 128 or 256 chars"; exit(1); } int numchars = (((int)startc+(int)numc-1) > 128) ? 256 : 128; //��� Find and select font that meets input criteria HWND hWnd = GetDesktopWindow(); assert(hWnd != 0); HDC hDC = GetDC(hWnd); assert(hDC != 0); HFONT hFont, hOldFont; OUTLINETEXTMETRIC tm; for(;;) { LOGFONT fontinfo; memset(&fontinfo,0,sizeof(fontinfo)); fontinfo.lfHeight = height; if (Flags & FLAGS_TT_BOLD) fontinfo.lfWeight = FW_BOLD; if (Flags & FLAGS_TT_ITALIC) fontinfo.lfItalic = TRUE; if (Flags & FLAGS_TT_UNDERLINE) fontinfo.lfUnderline = TRUE; if (Flags & FLAGS_TT_STRIKEOUT) fontinfo.lfStrikeOut = TRUE; if (Flags & FLAGS_TT_OEMCHARSET) fontinfo.lfCharSet = OEM_CHARSET; fontinfo.lfOutPrecision = OUT_TT_ONLY_PRECIS; strncpy(fontinfo.lfFaceName,ttname,sizeof(fontinfo.lfFaceName)); hFont = CreateFontIndirect(&fontinfo); if (!hFont) { cout << "��� Error: failed to get TrueType font with specified characteristics"; ReleaseDC(hWnd,hDC); exit(1); } hOldFont = (HFONT__*)SelectObject(hDC,hFont); memset(&tm,0,sizeof(tm)); GetOutlineTextMetrics(hDC,sizeof(tm),&tm); if (!width || tm.otmTextMetrics.tmMaxCharWidth <= width) { break; } else if (height <= 1) { cout << "��� Error: failed to get TrueType font with specified characteristics\n"; SelectObject(hDC,hOldFont); DeleteObject(hFont); ReleaseDC(hWnd,hDC); exit(1); } else { height--; SelectObject(hDC,hOldFont); } } //��� See if we can download bitmap for font... { GLYPHMETRICS glyph; MAT2 matrix; memset(&matrix,0,sizeof(matrix)); matrix.eM11.value = 1; matrix.eM22.value = 1; if (GetGlyphOutline(hDC,0,GGO_BITMAP,&glyph,0,0,&matrix) == GDI_ERROR) { cout << "��� Error: Can't capture data for specified font characteristics\n"; SelectObject(hDC,hOldFont); DeleteObject(hFont); ReleaseDC(hWnd,hDC); exit(1); } } //��� Output information about selected font if (!(Flags & FLAGS_QUIET)) { cout << "Capturing TrueType font '" << ttname << "'...\n"; cout << " Size: " << tm.otmTextMetrics.tmMaxCharWidth << " by " << tm.otmTextMetrics.tmHeight << endl; cout << " Character #" << (int)startc << " to #" << ((int)startc+(int)numc-1) << endl; if (tm.otmfsType & 0x1) cout << " *Licensed font*"; cout << " Attributes: "; switch (tm.otmTextMetrics.tmWeight) { case FW_THIN: cout << "Thin "; break; case FW_EXTRALIGHT: cout << "ExtraLight "; break; case FW_LIGHT: cout << "Light "; break; case FW_NORMAL: cout << "Normal "; break; case FW_MEDIUM: cout << "Medium "; break; case FW_SEMIBOLD: cout << "SemiBold "; break; case FW_BOLD: cout << "Bold "; break; case FW_EXTRABOLD: cout << "ExtraBold "; break; case FW_HEAVY: cout << "Heavy "; break; default: cout << "Wght(" << tm.otmTextMetrics.tmWeight << ") "; break; } if (tm.otmTextMetrics.tmItalic) cout << "Italic "; if (tm.otmTextMetrics.tmUnderlined) cout << "Underlined "; if (tm.otmTextMetrics.tmStruckOut) cout << "StruckOut "; if (tm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH) cout << "Variable-pitch "; else cout << "Fixed-pitch "; cout << endl; cout << " Family: "; if (tm.otmTextMetrics.tmPitchAndFamily & FF_MODERN) cout << "Modern "; if (tm.otmTextMetrics.tmPitchAndFamily & FF_ROMAN) cout << "Roman "; if (tm.otmTextMetrics.tmPitchAndFamily & FF_SCRIPT) cout << "Script "; if (tm.otmTextMetrics.tmPitchAndFamily & FF_SWISS) cout << "Swiss "; if (tm.otmTextMetrics.tmPitchAndFamily & FF_DECORATIVE) cout << "Decorative "; cout << endl; cout << " CharSet: "; switch (tm.otmTextMetrics.tmCharSet) { case ANSI_CHARSET: cout << "ANSI "; break; case SYMBOL_CHARSET: cout << "Symbol "; break; case OEM_CHARSET: cout << "OEM "; break; default: cout << "#" << tm.otmTextMetrics.tmCharSet; break; } cout << endl; if ((numchars > 128) && (Flags & FLAGS_TT_CP850)) { cout << " Map special characters to Codepage 850\n"; } } if (tm.otmTextMetrics.tmMaxCharWidth > 32) { cout << "��� Error: Maximum width must be less than or equal to 32"; SelectObject(hDC,hOldFont); DeleteObject(hFont); ReleaseDC(hWnd,hDC); exit(1); } //�� Font Header header.width = (ushort)tm.otmTextMetrics.tmMaxCharWidth; header.height = (ushort)tm.otmTextMetrics.tmHeight; // Only supports MONO non-COMPRESSED fonts header.compression = 0; if (tm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH) { // Variable header.type = (numchars > 128) ? GBERG_FNT_MONOVARIABLEEX : GBERG_FNT_MONOVARIABLE; header.bpc = (ushort)((((header.width + 7) >> 3) * header.height) + 1); }
CPDF_Font* CPDF_Document::AddWindowsFont(LOGFONTA* pLogFont, FX_BOOL bVert, FX_BOOL bTranslateName) { pLogFont->lfHeight = -1000; pLogFont->lfWidth = 0; HGDIOBJ hFont = CreateFontIndirectA(pLogFont); HDC hDC = CreateCompatibleDC(NULL); hFont = SelectObject(hDC, hFont); int tm_size = GetOutlineTextMetrics(hDC, 0, NULL); if (tm_size == 0) { hFont = SelectObject(hDC, hFont); DeleteObject(hFont); DeleteDC(hDC); return NULL; } LPBYTE tm_buf = FX_Alloc(BYTE, tm_size); OUTLINETEXTMETRIC* ptm = (OUTLINETEXTMETRIC*)tm_buf; GetOutlineTextMetrics(hDC, tm_size, ptm); int flags = 0, italicangle, ascend, descend, capheight, bbox[4]; if (pLogFont->lfItalic) { flags |= PDFFONT_ITALIC; } if ((pLogFont->lfPitchAndFamily & 3) == FIXED_PITCH) { flags |= PDFFONT_FIXEDPITCH; } if ((pLogFont->lfPitchAndFamily & 0xf8) == FF_ROMAN) { flags |= PDFFONT_SERIF; } if ((pLogFont->lfPitchAndFamily & 0xf8) == FF_SCRIPT) { flags |= PDFFONT_SCRIPT; } FX_BOOL bCJK = pLogFont->lfCharSet == CHINESEBIG5_CHARSET || pLogFont->lfCharSet == GB2312_CHARSET || pLogFont->lfCharSet == HANGEUL_CHARSET || pLogFont->lfCharSet == SHIFTJIS_CHARSET; CFX_ByteString basefont; if (bTranslateName && bCJK) { basefont = _FPDF_GetPSNameFromTT(hDC); } if (basefont.IsEmpty()) { basefont = pLogFont->lfFaceName; } italicangle = ptm->otmItalicAngle / 10; ascend = ptm->otmrcFontBox.top; descend = ptm->otmrcFontBox.bottom; capheight = ptm->otmsCapEmHeight; bbox[0] = ptm->otmrcFontBox.left; bbox[1] = ptm->otmrcFontBox.bottom; bbox[2] = ptm->otmrcFontBox.right; bbox[3] = ptm->otmrcFontBox.top; FX_Free(tm_buf); basefont.Replace(" ", ""); CPDF_Dictionary* pBaseDict = FX_NEW CPDF_Dictionary; pBaseDict->SetAtName("Type", "Font"); CPDF_Dictionary* pFontDict = pBaseDict; if (!bCJK) { if (pLogFont->lfCharSet == ANSI_CHARSET || pLogFont->lfCharSet == DEFAULT_CHARSET || pLogFont->lfCharSet == SYMBOL_CHARSET) { if (pLogFont->lfCharSet == SYMBOL_CHARSET) { flags |= PDFFONT_SYMBOLIC; } else { flags |= PDFFONT_NONSYMBOLIC; } pBaseDict->SetAtName(FX_BSTRC("Encoding"), "WinAnsiEncoding"); } else { flags |= PDFFONT_NONSYMBOLIC; int i; for (i = 0; i < sizeof g_FX_CharsetUnicodes / sizeof(FX_CharsetUnicodes); i ++) if (g_FX_CharsetUnicodes[i].m_Charset == pLogFont->lfCharSet) { break; } if (i < sizeof g_FX_CharsetUnicodes / sizeof(FX_CharsetUnicodes)) { CPDF_Dictionary* pEncoding = FX_NEW CPDF_Dictionary; pEncoding->SetAtName(FX_BSTRC("BaseEncoding"), "WinAnsiEncoding"); CPDF_Array* pArray = FX_NEW CPDF_Array; pArray->AddInteger(128); const FX_WCHAR* pUnicodes = g_FX_CharsetUnicodes[i].m_pUnicodes; for (int j = 0; j < 128; j ++) { CFX_ByteString name = PDF_AdobeNameFromUnicode(pUnicodes[j]); if (name.IsEmpty()) { pArray->AddName(FX_BSTRC(".notdef")); } else { pArray->AddName(name); } } pEncoding->SetAt(FX_BSTRC("Differences"), pArray); AddIndirectObject(pEncoding); pBaseDict->SetAtReference(FX_BSTRC("Encoding"), this, pEncoding); } } if (pLogFont->lfWeight > FW_MEDIUM && pLogFont->lfItalic) { basefont += ",BoldItalic"; } else if (pLogFont->lfWeight > FW_MEDIUM) { basefont += ",Bold"; } else if (pLogFont->lfItalic) { basefont += ",Italic"; } pBaseDict->SetAtName("Subtype", "TrueType"); pBaseDict->SetAtName("BaseFont", basefont); pBaseDict->SetAtNumber("FirstChar", 32); pBaseDict->SetAtNumber("LastChar", 255); int char_widths[224]; GetCharWidth(hDC, 32, 255, char_widths); CPDF_Array* pWidths = FX_NEW CPDF_Array; for (int i = 0; i < 224; i ++) { pWidths->AddInteger(char_widths[i]); } pBaseDict->SetAt("Widths", pWidths); } else { flags |= PDFFONT_NONSYMBOLIC; pFontDict = FX_NEW CPDF_Dictionary; CFX_ByteString cmap; CFX_ByteString ordering; int supplement; CPDF_Array* pWidthArray = FX_NEW CPDF_Array; switch (pLogFont->lfCharSet) { case CHINESEBIG5_CHARSET: cmap = bVert ? "ETenms-B5-V" : "ETenms-B5-H"; ordering = "CNS1"; supplement = 4; pWidthArray->AddInteger(1); _InsertWidthArray(hDC, 0x20, 0x7e, pWidthArray); break; case GB2312_CHARSET: cmap = bVert ? "GBK-EUC-V" : "GBK-EUC-H"; ordering = "GB1", supplement = 2; pWidthArray->AddInteger(7716); _InsertWidthArray(hDC, 0x20, 0x20, pWidthArray); pWidthArray->AddInteger(814); _InsertWidthArray(hDC, 0x21, 0x7e, pWidthArray); break; case HANGEUL_CHARSET: cmap = bVert ? "KSCms-UHC-V" : "KSCms-UHC-H"; ordering = "Korea1"; supplement = 2; pWidthArray->AddInteger(1); _InsertWidthArray(hDC, 0x20, 0x7e, pWidthArray); break; case SHIFTJIS_CHARSET: cmap = bVert ? "90ms-RKSJ-V" : "90ms-RKSJ-H"; ordering = "Japan1"; supplement = 5; pWidthArray->AddInteger(231); _InsertWidthArray(hDC, 0x20, 0x7d, pWidthArray); pWidthArray->AddInteger(326); _InsertWidthArray(hDC, 0xa0, 0xa0, pWidthArray); pWidthArray->AddInteger(327); _InsertWidthArray(hDC, 0xa1, 0xdf, pWidthArray); pWidthArray->AddInteger(631); _InsertWidthArray(hDC, 0x7e, 0x7e, pWidthArray); break; } pBaseDict->SetAtName("Subtype", "Type0"); pBaseDict->SetAtName("BaseFont", basefont); pBaseDict->SetAtName("Encoding", cmap); pFontDict->SetAt("W", pWidthArray); pFontDict->SetAtName("Type", "Font"); pFontDict->SetAtName("Subtype", "CIDFontType2"); pFontDict->SetAtName("BaseFont", basefont); CPDF_Dictionary* pCIDSysInfo = FX_NEW CPDF_Dictionary; pCIDSysInfo->SetAtString("Registry", "Adobe"); pCIDSysInfo->SetAtString("Ordering", ordering); pCIDSysInfo->SetAtInteger("Supplement", supplement); pFontDict->SetAt("CIDSystemInfo", pCIDSysInfo); CPDF_Array* pArray = FX_NEW CPDF_Array; pBaseDict->SetAt("DescendantFonts", pArray); AddIndirectObject(pFontDict); pArray->AddReference(this, pFontDict); } AddIndirectObject(pBaseDict); CPDF_Dictionary* pFontDesc = FX_NEW CPDF_Dictionary; pFontDesc->SetAtName("Type", "FontDescriptor"); pFontDesc->SetAtName("FontName", basefont); pFontDesc->SetAtInteger("Flags", flags); CPDF_Array* pBBox = FX_NEW CPDF_Array; for (int i = 0; i < 4; i ++) { pBBox->AddInteger(bbox[i]); } pFontDesc->SetAt("FontBBox", pBBox); pFontDesc->SetAtInteger("ItalicAngle", italicangle); pFontDesc->SetAtInteger("Ascent", ascend); pFontDesc->SetAtInteger("Descent", descend); pFontDesc->SetAtInteger("CapHeight", capheight); pFontDesc->SetAtInteger("StemV", pLogFont->lfWeight / 5); AddIndirectObject(pFontDesc); pFontDict->SetAtReference("FontDescriptor", this, pFontDesc); hFont = SelectObject(hDC, hFont); DeleteObject(hFont); DeleteDC(hDC); return LoadFont(pBaseDict); }
void SimpleFontData::platformInit() { m_syntheticBoldOffset = m_platformData.syntheticBold() ? 1.0f : 0.f; m_scriptCache = 0; m_scriptFontProperties = 0; m_isSystemFont = false; if (m_platformData.useGDI()) return initGDIFont(); if (!m_platformData.size()) { m_fontMetrics.reset(); m_avgCharWidth = 0; m_maxCharWidth = 0; return; } HDC hdc = GetDC(0); SaveDC(hdc); cairo_scaled_font_t* scaledFont = m_platformData.scaledFont(); const double metricsMultiplier = cairo_win32_scaled_font_get_metrics_factor(scaledFont) * m_platformData.size(); cairo_win32_scaled_font_select_font(scaledFont, hdc); TEXTMETRIC textMetrics; GetTextMetrics(hdc, &textMetrics); float ascent = textMetrics.tmAscent * metricsMultiplier; float descent = textMetrics.tmDescent * metricsMultiplier; float xHeight = ascent * 0.56f; // Best guess for xHeight for non-Truetype fonts. float lineGap = textMetrics.tmExternalLeading * metricsMultiplier; int faceLength = ::GetTextFace(hdc, 0, 0); Vector<WCHAR> faceName(faceLength); ::GetTextFace(hdc, faceLength, faceName.data()); m_isSystemFont = !wcscmp(faceName.data(), L"Lucida Grande"); ascent = ascentConsideringMacAscentHack(faceName.data(), ascent, descent); m_fontMetrics.setAscent(ascent); m_fontMetrics.setDescent(descent); m_fontMetrics.setLineGap(lineGap); m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap)); m_avgCharWidth = textMetrics.tmAveCharWidth * metricsMultiplier; m_maxCharWidth = textMetrics.tmMaxCharWidth * metricsMultiplier; OUTLINETEXTMETRIC metrics; if (GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics) > 0) { // This is a TrueType font. We might be able to get an accurate xHeight GLYPHMETRICS gm; MAT2 mat = { 1, 0, 0, 1 }; DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &mat); if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0) xHeight = gm.gmptGlyphOrigin.y * metricsMultiplier; } m_fontMetrics.setXHeight(xHeight); cairo_win32_scaled_font_done_font(scaledFont); RestoreDC(hdc, -1); ReleaseDC(0, hdc); }
BOOL bTestGOTM ( HDC hdc ) { ULONG row = 0; // screen row coordinate to print at HFONT hfont; HFONT hfontOriginal; LOGFONT lfnt; POUTLINETEXTMETRIC potm; ULONG cjotm; PSZ pszPitch, pszFamily; // Clear the screen to black. BitBlt(hdc, 0, 0, CX, CY, (HDC) 0, 0, 0, 0); // Get a font. memset(&lfnt, 0, sizeof(lfnt)); lstrcpy(lfnt.lfFaceName, "Arial"); lfnt.lfHeight = -14; lfnt.lfWeight = 400; if ((hfont = CreateFontIndirect(&lfnt)) == NULL) { DbgPrint("ft!bTestGOTM(): Logical font creation failed.\n"); return FALSE; } hfontOriginal = SelectObject(hdc, hfont); // Determine size needed for OTM. if ( (cjotm = (ULONG) GetOutlineTextMetrics(hdc, 0, (POUTLINETEXTMETRIC) NULL)) == (ULONG) 0 ) { DbgPrint("ft!bTestGOTM(): could not get size info from GetOutlineTextMetrics\n"); return FALSE; } // Allocate memory. if ( (potm = (POUTLINETEXTMETRIC) LocalAlloc(LPTR, cjotm)) == (POUTLINETEXTMETRIC) NULL ) { DbgPrint("ft!bTestGOTM(): LocalAlloc(LPTR, 0x%lx) failed\n", cjotm); return FALSE; } // Get the OTM. if ( GetOutlineTextMetrics(hdc, cjotm, potm) == (DWORD) 0 ) { LocalFree(potm); DbgPrint("ft!bTestGOTM(): GetOutlineTextMetrics call failed\n"); return FALSE; } // Print TEXTMETRIC. vPrintTM(hdc, &potm->otmTextMetrics); DbgBreakPoint(); // Print TEXTMETRIC. vPrintOTM(hdc, potm); DbgBreakPoint(); // Restore the font. SelectObject(hdc, hfontOriginal); DeleteObject(hfont); LocalFree(potm); return TRUE; }
CPDF_Font* CPDF_Document::AddWindowsFont(LOGFONTA* pLogFont, FX_BOOL bVert, FX_BOOL bTranslateName) { pLogFont->lfHeight = -1000; pLogFont->lfWidth = 0; HGDIOBJ hFont = CreateFontIndirectA(pLogFont); HDC hDC = CreateCompatibleDC(nullptr); hFont = SelectObject(hDC, hFont); int tm_size = GetOutlineTextMetrics(hDC, 0, nullptr); if (tm_size == 0) { hFont = SelectObject(hDC, hFont); DeleteObject(hFont); DeleteDC(hDC); return nullptr; } LPBYTE tm_buf = FX_Alloc(BYTE, tm_size); OUTLINETEXTMETRIC* ptm = reinterpret_cast<OUTLINETEXTMETRIC*>(tm_buf); GetOutlineTextMetrics(hDC, tm_size, ptm); int flags = CalculateFlags(false, pLogFont->lfItalic != 0, (pLogFont->lfPitchAndFamily & 3) == FIXED_PITCH, (pLogFont->lfPitchAndFamily & 0xf8) == FF_ROMAN, (pLogFont->lfPitchAndFamily & 0xf8) == FF_SCRIPT, pLogFont->lfCharSet == FXFONT_SYMBOL_CHARSET); bool bCJK = pLogFont->lfCharSet == FXFONT_CHINESEBIG5_CHARSET || pLogFont->lfCharSet == FXFONT_GB2312_CHARSET || pLogFont->lfCharSet == FXFONT_HANGUL_CHARSET || pLogFont->lfCharSet == FXFONT_SHIFTJIS_CHARSET; CFX_ByteString basefont; if (bTranslateName && bCJK) basefont = FPDF_GetPSNameFromTT(hDC); if (basefont.IsEmpty()) basefont = pLogFont->lfFaceName; int italicangle = ptm->otmItalicAngle / 10; int ascend = ptm->otmrcFontBox.top; int descend = ptm->otmrcFontBox.bottom; int capheight = ptm->otmsCapEmHeight; int bbox[4] = {ptm->otmrcFontBox.left, ptm->otmrcFontBox.bottom, ptm->otmrcFontBox.right, ptm->otmrcFontBox.top}; FX_Free(tm_buf); basefont.Replace(" ", ""); CPDF_Dictionary* pBaseDict = new CPDF_Dictionary(m_pByteStringPool); pBaseDict->SetNameFor("Type", "Font"); CPDF_Dictionary* pFontDict = pBaseDict; if (!bCJK) { if (pLogFont->lfCharSet == FXFONT_ANSI_CHARSET || pLogFont->lfCharSet == FXFONT_DEFAULT_CHARSET || pLogFont->lfCharSet == FXFONT_SYMBOL_CHARSET) { pBaseDict->SetNameFor("Encoding", "WinAnsiEncoding"); } else { CalculateEncodingDict(pLogFont->lfCharSet, pBaseDict); } int char_widths[224]; GetCharWidth(hDC, 32, 255, char_widths); CPDF_Array* pWidths = new CPDF_Array; for (size_t i = 0; i < 224; i++) pWidths->AddInteger(char_widths[i]); ProcessNonbCJK(pBaseDict, pLogFont->lfWeight > FW_MEDIUM, pLogFont->lfItalic != 0, basefont, pWidths); } else { pFontDict = ProcessbCJK(pBaseDict, pLogFont->lfCharSet, bVert, basefont, [&hDC](FX_WCHAR start, FX_WCHAR end, CPDF_Array* widthArr) { InsertWidthArray(hDC, start, end, widthArr); }); } AddIndirectObject(pBaseDict); CPDF_Array* pBBox = new CPDF_Array; for (int i = 0; i < 4; i++) pBBox->AddInteger(bbox[i]); CPDF_Dictionary* pFontDesc = CalculateFontDesc(this, basefont, flags, italicangle, ascend, descend, pBBox, pLogFont->lfWeight / 5); pFontDesc->SetIntegerFor("CapHeight", capheight); pFontDict->SetReferenceFor("FontDescriptor", this, AddIndirectObject(pFontDesc)); hFont = SelectObject(hDC, hFont); DeleteObject(hFont); DeleteDC(hDC); return LoadFont(pBaseDict); }
void font_instance::LoadGlyph(int glyph_id) { if ( pFont == NULL ) { return; } InitTheFace(); #ifndef USE_PANGO_WIN32 if ( !FT_IS_SCALABLE(theFace) ) { return; // bitmap font } #endif if ( id_to_no.find(glyph_id) == id_to_no.end() ) { Geom::PathBuilder path_builder; if ( nbGlyph >= maxGlyph ) { maxGlyph=2*nbGlyph+1; glyphs=(font_glyph*)realloc(glyphs,maxGlyph*sizeof(font_glyph)); } font_glyph n_g; n_g.pathvector=NULL; n_g.bbox[0]=n_g.bbox[1]=n_g.bbox[2]=n_g.bbox[3]=0; n_g.h_advance = 0; n_g.v_advance = 0; n_g.h_width = 0; n_g.v_width = 0; bool doAdd=false; #ifdef USE_PANGO_WIN32 #ifndef GGO_UNHINTED // For compatibility with old SDKs. #define GGO_UNHINTED 0x0100 #endif MAT2 identity = {{0,1},{0,0},{0,0},{0,1}}; OUTLINETEXTMETRIC otm; GetOutlineTextMetrics(daddy->hScreenDC, sizeof(otm), &otm); GLYPHMETRICS metrics; DWORD bufferSize=GetGlyphOutline (daddy->hScreenDC, glyph_id, GGO_GLYPH_INDEX | GGO_NATIVE | GGO_UNHINTED, &metrics, 0, NULL, &identity); double scale=1.0/daddy->fontSize; n_g.h_advance=metrics.gmCellIncX*scale; n_g.v_advance=otm.otmTextMetrics.tmHeight*scale; n_g.h_width=metrics.gmBlackBoxX*scale; n_g.v_width=metrics.gmBlackBoxY*scale; if ( bufferSize == GDI_ERROR) { // shit happened } else if ( bufferSize == 0) { // character has no visual representation, but is valid (eg whitespace) doAdd=true; } else { char *buffer = new char[bufferSize]; if ( GetGlyphOutline (daddy->hScreenDC, glyph_id, GGO_GLYPH_INDEX | GGO_NATIVE | GGO_UNHINTED, &metrics, bufferSize, buffer, &identity) <= 0 ) { // shit happened } else { // Platform SDK is rubbish, read KB87115 instead DWORD polyOffset=0; while ( polyOffset < bufferSize ) { TTPOLYGONHEADER const *polyHeader=(TTPOLYGONHEADER const *)(buffer+polyOffset); if (polyOffset+polyHeader->cb > bufferSize) break; if (polyHeader->dwType == TT_POLYGON_TYPE) { path_builder.moveTo(pointfx_to_nrpoint(polyHeader->pfxStart, scale)); DWORD curveOffset=polyOffset+sizeof(TTPOLYGONHEADER); while ( curveOffset < polyOffset+polyHeader->cb ) { TTPOLYCURVE const *polyCurve=(TTPOLYCURVE const *)(buffer+curveOffset); POINTFX const *p=polyCurve->apfx; POINTFX const *endp=p+polyCurve->cpfx; switch (polyCurve->wType) { case TT_PRIM_LINE: while ( p != endp ) path_builder.lineTo(pointfx_to_nrpoint(*p++, scale)); break; case TT_PRIM_QSPLINE: { g_assert(polyCurve->cpfx >= 2); // The list of points specifies one or more control points and ends with the end point. // The intermediate points (on the curve) are the points between the control points. Geom::Point this_control = pointfx_to_nrpoint(*p++, scale); while ( p+1 != endp ) { // Process all "midpoints" (all points except the last) Geom::Point new_control = pointfx_to_nrpoint(*p++, scale); path_builder.quadTo(this_control, (new_control+this_control)/2); this_control = new_control; } Geom::Point end = pointfx_to_nrpoint(*p++, scale); path_builder.quadTo(this_control, end); } break; case 3: // TT_PRIM_CSPLINE g_assert(polyCurve->cpfx % 3 == 0); while ( p != endp ) { path_builder.curveTo(pointfx_to_nrpoint(p[0], scale), pointfx_to_nrpoint(p[1], scale), pointfx_to_nrpoint(p[2], scale)); p += 3; } break; } curveOffset += sizeof(TTPOLYCURVE)+sizeof(POINTFX)*(polyCurve->cpfx-1); } } polyOffset += polyHeader->cb; } doAdd=true; } delete [] buffer; } #else if (FT_Load_Glyph (theFace, glyph_id, FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)) { // shit happened } else { if ( FT_HAS_HORIZONTAL(theFace) ) { n_g.h_advance=((double)theFace->glyph->metrics.horiAdvance)/((double)theFace->units_per_EM); n_g.h_width=((double)theFace->glyph->metrics.width)/((double)theFace->units_per_EM); } else { n_g.h_width=n_g.h_advance=((double)(theFace->bbox.xMax-theFace->bbox.xMin))/((double)theFace->units_per_EM); } if ( FT_HAS_VERTICAL(theFace) ) { n_g.v_advance=((double)theFace->glyph->metrics.vertAdvance)/((double)theFace->units_per_EM); n_g.v_width=((double)theFace->glyph->metrics.height)/((double)theFace->units_per_EM); } else { n_g.v_width=n_g.v_advance=((double)theFace->height)/((double)theFace->units_per_EM); } if ( theFace->glyph->format == ft_glyph_format_outline ) { FT_Outline_Funcs ft2_outline_funcs = { ft2_move_to, ft2_line_to, ft2_conic_to, ft2_cubic_to, 0, 0 }; FT2GeomData user(path_builder, 1.0/((double)theFace->units_per_EM)); FT_Outline_Decompose (&theFace->glyph->outline, &ft2_outline_funcs, &user); } doAdd=true; } #endif path_builder.finish(); if ( doAdd ) { Geom::PathVector pv = path_builder.peek(); // close all paths for (Geom::PathVector::iterator i = pv.begin(); i != pv.end(); ++i) { i->close(); } if ( !pv.empty() ) { n_g.pathvector = new Geom::PathVector(pv); Geom::OptRect bounds = bounds_exact(*n_g.pathvector); if (bounds) { n_g.bbox[0] = bounds->left(); n_g.bbox[1] = bounds->top(); n_g.bbox[2] = bounds->right(); n_g.bbox[3] = bounds->bottom(); } } glyphs[nbGlyph]=n_g; id_to_no[glyph_id]=nbGlyph; nbGlyph++; } } else { } }
LPTSTR ASSISTANT::Text::GetTtfName() { static _TCHAR tszTtfName[512]; HKEY hKeyMachine; LONG regErr = RegOpenKeyEx (HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"), NULL,KEY_READ,&hKeyMachine); if ( regErr != ERROR_SUCCESS ) { LONG regErr = RegOpenKeyEx (HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Fonts"), NULL,KEY_READ,&hKeyMachine); if ( regErr != ERROR_SUCCESS ) { return NULL; } } DWORD subValues; regErr = RegQueryInfoKey(hKeyMachine, NULL, NULL, NULL, NULL, NULL, NULL, &subValues, NULL, NULL, NULL, NULL); if ( regErr != ERROR_SUCCESS ) { return NULL; } HRESULT hr = ::CoInitialize(NULL); HDC hdc = ::CreateCompatibleDC(NULL); DWORD dwType; _TCHAR tszEntryName[512]; _TCHAR tszEntryValue[512]; HFONT font = CreateFontIndirect(&m_logFont); UINT cbData; LPOUTLINETEXTMETRIC lpoltm; SelectObject(hdc, font); cbData = GetOutlineTextMetrics (hdc, 0, NULL); DeleteObject(font); _TCHAR tszFontFace[512]; if (cbData == 0) { _tcscpy(tszFontFace, m_logFont.lfFaceName); } else { lpoltm = (LPOUTLINETEXTMETRIC)LocalAlloc (LPTR, cbData); GetOutlineTextMetrics (hdc, cbData, lpoltm); _tcscpy(tszFontFace, (_TCHAR *)((DWORD) lpoltm + lpoltm->otmpFaceName)); } bool bFoundFontInfo = false; for (int i = 0; i < subValues && !bFoundFontInfo; i++) { unsigned long entryNameLength = 512 * sizeof _TCHAR; unsigned long entryValueLength = 512 * sizeof _TCHAR; if (RegEnumValue(hKeyMachine, i, tszEntryName, &entryNameLength, NULL, &dwType, (unsigned char *)tszEntryValue, &entryValueLength) != ERROR_SUCCESS) { continue; } _TCHAR tszFaceName[512]; _tcscpy(tszFaceName, tszEntryName); _TCHAR *p = _tcsrchr(tszFaceName, '('); if (p != NULL) *p = '\0'; if (tszFaceName[_tcslen(tszFaceName) - 1] == _T(' ')) tszFaceName[_tcslen(tszFaceName) - 1] = _T('\0'); if (_tcscmp(tszFontFace, tszFaceName) == 0) { bFoundFontInfo = true; UINT nStringLength = _tcslen(tszEntryValue); _tcscpy(tszTtfName, tszEntryValue); tszTtfName[nStringLength] = '\0'; } } ::DeleteDC(hdc); ::CoUninitialize(); RegCloseKey(hKeyMachine); if (bFoundFontInfo) return tszTtfName; else return NULL; }