/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// if aBoundingBoxType is LOOSE_INK_EXTENTS // and the underlying cairo font may be antialiased, // we can't trust Windows to have considered all the pixels // so we need to add "padding" to the bounds. // (see bugs 475968, 439831, compare also bug 445087) if (aBoundingBoxType == LOOSE_INK_EXTENTS &&
mAntialiasOption != kAntialiasNone && metrics.mBoundingBox.Width() > 0) {
metrics.mBoundingBox.MoveByX(-aTextRun->GetAppUnitsPerDevUnit());
metrics.mBoundingBox.SetWidth(metrics.mBoundingBox.Width() +
aTextRun->GetAppUnitsPerDevUnit() * 3);
}
return metrics;
}
void gfxGDIFont::Initialize() {
NS_ASSERTION(!mMetrics, "re-creating metrics? this will leak");
LOGFONTW logFont;
if (mAdjustedSize == 0.0) {
mAdjustedSize = GetAdjustedSize(); if (FontSizeAdjust::Tag(mStyle.sizeAdjustBasis) !=
FontSizeAdjust::Tag::None) { 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();
// Unless the font was so small that GDI metrics rounded to zero, // calculate the properly adjusted size, and then proceed // to recreate mFont and recalculate metrics if (mMetrics->emHeight > 0.0) {
gfxFloat aspect; switch (FontSizeAdjust::Tag(mStyle.sizeAdjustBasis)) { default:
MOZ_ASSERT_UNREACHABLE("unhandled sizeAdjustBasis?");
aspect = 0.0; break; case FontSizeAdjust::Tag::ExHeight:
aspect = mMetrics->xHeight / mMetrics->emHeight; break; case FontSizeAdjust::Tag::CapHeight:
aspect = mMetrics->capHeight / mMetrics->emHeight; break; case FontSizeAdjust::Tag::ChWidth: {
gfxFloat advance = GetCharAdvance('0');
aspect = advance > 0.0 ? advance / mMetrics->emHeight : 0.5; break;
} case FontSizeAdjust::Tag::IcWidth: case FontSizeAdjust::Tag::IcHeight: { bool vertical = FontSizeAdjust::Tag(mStyle.sizeAdjustBasis) ==
FontSizeAdjust::Tag::IcHeight;
gfxFloat advance = GetCharAdvance(kWaterIdeograph, vertical);
aspect = advance > 0.0 ? advance / mMetrics->emHeight : 1.0; break;
}
} if (aspect > 0.0) { // If we created a shaper above (to measure glyphs), discard it so // we get a new one for the adjusted scaling. delete mHarfBuzzShaper.exchange(nullptr);
mAdjustedSize = mStyle.GetAdjustedSize(aspect);
}
}
// delete the temporary font and metrics
::DeleteObject(mFont);
mFont = nullptr; delete mMetrics;
mMetrics = nullptr;
} else {
mAdjustedSize = 0.0;
}
}
}
// (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 (mNeedsSyntheticBold && GetFontEntry()->IsLocalUserFont()) {
mApplySyntheticBold = true;
}
// this may end up being zero
mAdjustedSize = ROUND(mAdjustedSize);
FillLogFont(logFont, mAdjustedSize);
mFont = ::CreateFontIndirectW(&logFont);
mMetrics = new gfxFont::Metrics;
::memset(mMetrics, 0, sizeof(*mMetrics));
const MAT2 kIdentityMatrix = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
GLYPHMETRICS gm;
DWORD len = GetGlyphOutlineW(dc.GetDC(), char16_t('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;
}
len = GetGlyphOutlineW(dc.GetDC(), char16_t('H'), GGO_METRICS, &gm, 0,
nullptr, &kIdentityMatrix); if (len == GDI_ERROR || gm.gmptGlyphOrigin.y <= 0) {
mMetrics->capHeight = metrics.tmAscent - metrics.tmInternalLeading;
} else {
mMetrics->capHeight = 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;
}
void gfxGDIFont::FillLogFont(LOGFONTW& aLogFont, gfxFloat aSize) {
GDIFontEntry* fe = static_cast<GDIFontEntry*>(GetFontEntry());
// Figure out the lfWeight value to use for GDI font selection, // or zero to use the entry's current LOGFONT value. LONG weight; if (fe->IsUserFont()) { if (fe->IsLocalUserFont()) { // for local user fonts, don't change the original weight // in the entry's logfont, because that could alter the // choice of actual face used (bug 724231)
weight = 0;
} else { // avoid GDI synthetic bold which occurs when weight // specified is >= font data weight + 200
weight = mNeedsSyntheticBold ? 700 : 200;
}
} else { // GDI doesn't support variation fonts, so for system fonts we know // that the entry has only a single weight, not a range.
MOZ_ASSERT(fe->Weight().IsSingle());
weight = mNeedsSyntheticBold ? 700 : fe->Weight().Min().ToIntRounded();
}
fe->FillLogFont(&aLogFont, weight, aSize);
}
uint32_t gfxGDIFont::GetGlyph(uint32_t aUnicode, uint32_t aVarSelector) { // Callback used only for fonts that lack a 'cmap' table.
// We don't support variation selector sequences or non-BMP characters // in the legacy bitmap, vector or postscript fonts that might use // this code path. if (aUnicode > 0xffff || aVarSelector) { return 0;
}
if (!mGlyphIDs) {
mGlyphIDs = MakeUnique<nsTHashMap<nsUint32HashKey, uint32_t>>(64);
}
uint32_t gid; if (mGlyphIDs->Get(aUnicode, &gid)) { return gid;
}
wchar_t ch = aUnicode;
WORD glyph;
HRESULT ret = ScriptGetCMap(nullptr, &mScriptCache, &ch, 1, 0, &glyph); if (ret != S_OK) {
AutoDC dc;
AutoSelectFont fs(dc.GetDC(), GetHFONT()); if (ret == E_PENDING) { // Try ScriptGetCMap again now that we've set up the font.
ret = ScriptGetCMap(dc.GetDC(), &mScriptCache, &ch, 1, 0, &glyph);
} if (ret != S_OK) { // If ScriptGetCMap still failed, fall back to GetGlyphIndicesW // (see bug 1105807).
DWORD ret = GetGlyphIndicesW(dc.GetDC(), &ch, 1, &glyph,
GGI_MARK_NONEXISTING_GLYPHS); if (ret == GDI_ERROR || glyph == 0xFFFF) {
glyph = 0;
}
}
}
if (gm.gmBlackBoxX == 1 && gm.gmBlackBoxY == 1 &&
!GetGlyphOutlineW(dc, aGID, GGO_NATIVE | GGO_GLYPH_INDEX, &gm, 0, nullptr,
&kIdentityMatrix)) { // Workaround for GetGlyphOutline returning 1x1 bounding box // for <space> glyph that is in fact empty.
gm.gmBlackBoxX = 0;
gm.gmBlackBoxY = 0;
} elseif (gm.gmBlackBoxX > 0 && !aTight) { // The bounding box reported by Windows supposedly contains the glyph's // "black" area; however, antialiasing (especially with ClearType) means // that the actual image that needs to be rendered may "bleed" into the // adjacent pixels, mainly on the right side.
gm.gmptGlyphOrigin.x -= 1;
gm.gmBlackBoxX += 3;
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.2Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.