/* -*- 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/. */
// Cleartype can be dynamically enabled/disabled, so we have to allow for // dynamically updating it. static BYTE GetSystemTextQuality() { BOOL font_smoothing;
UINT smoothing_type;
if (!SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0)) { return DEFAULT_QUALITY;
}
if (font_smoothing) { if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &smoothing_type,
0)) { return DEFAULT_QUALITY;
}
if (smoothing_type == FE_FONTSMOOTHINGCLEARTYPE) { return CLEARTYPE_QUALITY;
}
// "Retrieves a contrast value that is used in ClearType smoothing. Valid // contrast values are from 1000 to 2200. The default value is 1400." staticFLOAT GetSystemGDIGamma() {
UINT value = 0; if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &value, 0) ||
value < 1000 || value > 2200) {
value = 1400;
} return value / 1000.0f;
}
//////////////////////////////////////////////////////////////////////////////// // gfxDWriteFont
gfxDWriteFont::gfxDWriteFont(const RefPtr<UnscaledFontDWrite>& aUnscaledFont,
gfxFontEntry* aFontEntry, const gfxFontStyle* aFontStyle,
RefPtr<IDWriteFontFace> aFontFace,
AntialiasOption anAAOption)
: gfxFont(aUnscaledFont, aFontEntry, aFontStyle, anAAOption),
mFontFace(aFontFace ? aFontFace : aUnscaledFont->GetFontFace()),
mUseSubpixelPositions(false),
mAllowManualShowGlyphs(true),
mAzureScaledFontUsedClearType(false) { // If the IDWriteFontFace1 interface is available, we can use that for // faster glyph width retrieval.
mFontFace->QueryInterface(__uuidof(IDWriteFontFace1),
(void**)getter_AddRefs(mFontFace1)); // If a fake-bold effect is needed, determine whether we're using DWrite's // "simulation" or applying our multi-strike "synthetic bold". if (aFontStyle->NeedsSyntheticBold(aFontEntry)) { switch (StaticPrefs::gfx_font_rendering_directwrite_bold_simulation()) { case 0: // never use the DWrite simulation
mApplySyntheticBold = true; break; case 1: // use DWrite simulation for installed fonts except COLR fonts, // but not webfonts
mApplySyntheticBold =
aFontEntry->mIsDataUserFont ||
aFontEntry->HasFontTable(TRUETYPE_TAG('C', 'O', 'L', 'R')); break; default: // always use DWrite bold simulation, except for COLR fonts
mApplySyntheticBold =
aFontEntry->HasFontTable(TRUETYPE_TAG('C', 'O', 'L', 'R')); break;
}
}
ComputeMetrics(anAAOption);
}
if (XRE_IsParentProcess()) {
UpdateSystemTextVars();
} else { // UpdateClearTypeVars doesn't update the vars in non parent processes, but // it does set sForceGDIClassicEnabled so we still need to call it.
UpdateClearTypeVars();
}
DWriteSettings::Initialize();
void gfxDWriteFont::SystemTextQualityChanged() { // If ClearType status has changed, update our value,
Factory::SetSystemTextQuality(gfxVars::SystemTextQuality()); // flush cached stuff that depended on the old setting, and force // reflow everywhere to ensure we are using correct glyph metrics.
gfxPlatform::FlushFontAndWordCaches();
gfxPlatform::ForceGlobalReflow(gfxPlatform::GlobalReflowFlags::None);
}
/* static */ void gfxDWriteFont::UpdateClearTypeVars() { // We don't force GDI classic if the cleartype rendering mode pref is set to // something valid.
int32_t renderingModePref =
Preferences::GetInt(GFX_CLEARTYPE_PARAMS_MODE, -1); if (renderingModePref < 0 || renderingModePref > 5) {
renderingModePref = -1;
}
sForceGDIClassicEnabled = (renderingModePref == -1);
if (!XRE_IsParentProcess()) { return;
}
if (!Factory::GetDWriteFactory()) { return;
}
// First set sensible hard coded defaults. float clearTypeLevel = 1.0f; float enhancedContrast = 1.0f; float gamma = 2.2f; int pixelGeometry = DWRITE_PIXEL_GEOMETRY_RGB; int renderingMode = DWRITE_RENDERING_MODE_DEFAULT;
// Override these from DWrite function if available.
RefPtr<IDWriteRenderingParams> defaultRenderingParams;
HRESULT hr = Factory::GetDWriteFactory()->CreateRenderingParams(
getter_AddRefs(defaultRenderingParams)); if (SUCCEEDED(hr) && defaultRenderingParams) {
clearTypeLevel = defaultRenderingParams->GetClearTypeLevel();
// For enhanced contrast, we only use the default if the user has set it // in the registry (by using the ClearType Tuner). // XXXbobowen it seems slightly odd that we do this and only for enhanced // contrast, but this reproduces previous functionality from // gfxWindowsPlatform::SetupClearTypeParams.
HKEY hKey; LONG res = RegOpenKeyExW(DISPLAY1_REGISTRY_KEY, 0, KEY_READ, &hKey); if (res == ERROR_SUCCESS) {
res = RegQueryValueExW(hKey, ENHANCED_CONTRAST_VALUE_NAME, nullptr,
nullptr, nullptr, nullptr); if (res == ERROR_SUCCESS) {
enhancedContrast = defaultRenderingParams->GetEnhancedContrast();
}
RegCloseKey(hKey);
}
// Finally override from prefs if valid values are set. If ClearType is // turned off we just use the default params, this reproduces the previous // functionality that was spread across gfxDWriteFont::GetScaledFont and // gfxWindowsPlatform::SetupClearTypeParams, but it seems odd because the // default params will still be the ClearType ones although we won't use the // anti-alias for ClearType because of GetSystemDefaultAAMode. if (gfxVars::SystemTextQuality() == CLEARTYPE_QUALITY) {
int32_t prefInt = Preferences::GetInt(GFX_CLEARTYPE_PARAMS_LEVEL, -1); if (prefInt >= 0 && prefInt <= 100) {
clearTypeLevel = float(prefInt / 100.0);
}
// renderingModePref is retrieved and validated above. if (renderingModePref != -1) {
renderingMode = renderingModePref;
}
}
if (gfxVars::SystemTextClearTypeLevel() != clearTypeLevel) {
gfxVars::SetSystemTextClearTypeLevel(clearTypeLevel);
}
if (gfxVars::SystemTextEnhancedContrast() != enhancedContrast) {
gfxVars::SetSystemTextEnhancedContrast(enhancedContrast);
}
if (gfxVars::SystemTextGamma() != gamma) {
gfxVars::SetSystemTextGamma(gamma);
}
if (gfxVars::SystemTextPixelGeometry() != pixelGeometry) {
gfxVars::SetSystemTextPixelGeometry(pixelGeometry);
}
if (gfxVars::SystemTextRenderingMode() != renderingMode) {
gfxVars::SetSystemTextRenderingMode(renderingMode);
}
#if 0 // Set cairo dwrite params in the parent process where it might still be // needed for printing. We use the validated pref int directly for rendering // mode, because a negative (i.e. not set) rendering mode is also used for // deciding on forcing GDI in cairo.
cairo_dwrite_set_cleartype_params(gamma, enhancedContrast, clearTypeLevel,
pixelGeometry, renderingModePref); #endif
}
if (GetAdjustedSize() > 0.0 && mStyle.sizeAdjust >= 0.0 &&
FontSizeAdjust::Tag(mStyle.sizeAdjustBasis) !=
FontSizeAdjust::Tag::None) { // For accurate measurement during the font-size-adjust computations; // these may be reset later according to the adjusted size.
mUseSubpixelPositions = true;
mFUnitsConvFactor = float(mAdjustedSize / fontMetrics.designUnitsPerEm);
gfxFloat aspect; switch (FontSizeAdjust::Tag(mStyle.sizeAdjustBasis)) { default:
MOZ_ASSERT_UNREACHABLE("unhandled sizeAdjustBasis?");
aspect = 0.0; break; case FontSizeAdjust::Tag::ExHeight:
aspect = (gfxFloat)fontMetrics.xHeight / fontMetrics.designUnitsPerEm; break; case FontSizeAdjust::Tag::CapHeight:
aspect = (gfxFloat)fontMetrics.capHeight / fontMetrics.designUnitsPerEm; break; case FontSizeAdjust::Tag::ChWidth: {
gfxFloat advance = GetCharAdvance('0');
aspect = advance > 0.0 ? advance / mAdjustedSize : 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 / mAdjustedSize : 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);
}
}
// Update now that we've adjusted the size if necessary.
mFUnitsConvFactor = float(mAdjustedSize / fontMetrics.designUnitsPerEm);
// Note that GetMeasuringMode depends on mAdjustedSize if ((anAAOption == gfxFont::kAntialiasDefault && UsingClearType() &&
GetMeasuringMode() == DWRITE_MEASURING_MODE_NATURAL) ||
anAAOption == gfxFont::kAntialiasSubpixel) {
mUseSubpixelPositions = true; // note that this may be reset to FALSE if we determine that a bitmap // strike is going to be used
} else {
mUseSubpixelPositions = false;
}
gfxDWriteFontEntry* fe = static_cast<gfxDWriteFontEntry*>(mFontEntry.get()); if (fe->IsCJKFont() && HasBitmapStrikeForSize(NS_lround(mAdjustedSize))) {
mAdjustedSize = NS_lround(mAdjustedSize);
mUseSubpixelPositions = false; // if we have bitmaps, we need to tell Cairo NOT to use subpixel AA, // to avoid the manual-subpixel codepath in cairo-d2d-surface.cpp // which fails to render bitmap glyphs (see bug 626299). // This option will be passed to the cairo_dwrite_scaled_font_t // after creation.
mAllowManualShowGlyphs = false;
}
// try to get aveCharWidth from the OS/2 table, fall back to measuring 'x' // if the table is not available or if using hinted/pixel-snapped widths if (mUseSubpixelPositions) {
mMetrics.aveCharWidth = 0;
gfxFontEntry::AutoTable os2Table(GetFontEntry(),
TRUETYPE_TAG('O', 'S', '/', '2')); if (os2Table) {
uint32_t len; const OS2Table* os2 = reinterpret_cast<const OS2Table*>(hb_blob_get_data(os2Table, &len)); if (len >= 4) { // Not checking against sizeof(mozilla::OS2Table) here because older // versions of the table have different sizes; we only need the first // two 16-bit fields here.
mMetrics.aveCharWidth = int16_t(os2->xAvgCharWidth) * mFUnitsConvFactor;
}
}
}
if (mMetrics.aveCharWidth < 1) {
mMetrics.aveCharWidth = GetCharAdvance('x'); if (mMetrics.aveCharWidth < 1) { // Let's just assume the X is square.
mMetrics.aveCharWidth = fontMetrics.xHeight * mFUnitsConvFactor;
}
}
bool hasStrike = false; // not really a loop, but this lets us use 'break' to skip out of the block // as soon as we know the answer, and skips it altogether if the table is // not present while (exists) { if (len < sizeof(EBLCHeader)) { break;
} const EBLCHeader* hdr = reinterpret_cast<const EBLCHeader*>(tableData); if (hdr->version != 0x00020000) { break;
}
uint32_t numSizes = hdr->numSizes; if (numSizes > 0xffff) { // sanity-check, prevent overflow below break;
} if (len < sizeof(EBLCHeader) + numSizes * sizeof(BitmapSizeTable)) { break;
} const BitmapSizeTable* sizeTable = reinterpret_cast<const BitmapSizeTable*>(hdr + 1); for (uint32_t i = 0; i < numSizes; ++i, ++sizeTable) { if (sizeTable->ppemX == aSize && sizeTable->ppemY == aSize) { // we ignore a strike that contains fewer than 4 glyphs, // as that probably indicates a font such as Courier New // that provides bitmaps ONLY for the "shading" characters // U+2591..2593
hasStrike = (uint16_t(sizeTable->endGlyphIndex) >=
uint16_t(sizeTable->startGlyphIndex) + 3); break;
}
} // if we reach here, we didn't find a strike; unconditionally break // out of the while-loop block break;
}
mFontFace->ReleaseFontTable(tableContext);
if (hasStrike) { returntrue;
}
// if we didn't find a real strike, check if the font calls for scaling // another bitmap to this size
hr = mFontFace->TryGetFontTable(DWRITE_MAKE_OPENTYPE_TAG('E', 'B', 'S', 'C'),
(constvoid**)&tableData, &len, &tableContext,
&exists); if (FAILED(hr)) { returnfalse;
}
while (exists) { if (len < sizeof(EBSCHeader)) { break;
} const EBSCHeader* hdr = reinterpret_cast<const EBSCHeader*>(tableData); if (hdr->version != 0x00020000) { break;
}
uint32_t numSizes = hdr->numSizes; if (numSizes > 0xffff) { break;
} if (len < sizeof(EBSCHeader) + numSizes * sizeof(BitmapScaleTable)) { break;
} const BitmapScaleTable* scaleTable = reinterpret_cast<const BitmapScaleTable*>(hdr + 1); for (uint32_t i = 0; i < numSizes; ++i, ++scaleTable) { if (scaleTable->ppemX == aSize && scaleTable->ppemY == aSize) {
hasStrike = true; break;
}
} break;
}
mFontFace->ReleaseFontTable(tableContext);
// 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 &&
GetMeasuringMode() == DWRITE_MEASURING_MODE_GDI_CLASSIC &&
metrics.mBoundingBox.Width() > 0) {
metrics.mBoundingBox.MoveByX(-aTextRun->GetAppUnitsPerDevUnit());
metrics.mBoundingBox.SetWidth(metrics.mBoundingBox.Width() +
aTextRun->GetAppUnitsPerDevUnit() * 3);
}
gfxFloat gfxDWriteFont::MeasureGlyphWidth(uint16_t aGlyph) {
MOZ_SEH_TRY {
HRESULT hr; if (mFontFace1) {
int32_t advance; if (mUseSubpixelPositions) {
hr = mFontFace1->GetDesignGlyphAdvances(1, &aGlyph, &advance, FALSE); if (SUCCEEDED(hr)) { return advance * mFUnitsConvFactor;
}
} else {
hr = mFontFace1->GetGdiCompatibleGlyphAdvances( FLOAT(mAdjustedSize), 1.0f, nullptr,
GetMeasuringMode() == DWRITE_MEASURING_MODE_GDI_NATURAL, FALSE, 1,
&aGlyph, &advance); if (SUCCEEDED(hr)) { return NS_lround(advance * mFUnitsConvFactor);
}
}
} else {
DWRITE_GLYPH_METRICS metrics; if (mUseSubpixelPositions) {
hr = mFontFace->GetDesignGlyphMetrics(&aGlyph, 1, &metrics, FALSE); if (SUCCEEDED(hr)) { return metrics.advanceWidth * mFUnitsConvFactor;
}
} else {
hr = mFontFace->GetGdiCompatibleGlyphMetrics( FLOAT(mAdjustedSize), 1.0f, nullptr,
GetMeasuringMode() == DWRITE_MEASURING_MODE_GDI_NATURAL, &aGlyph, 1,
&metrics, FALSE); if (SUCCEEDED(hr)) { return NS_lround(metrics.advanceWidth * mFUnitsConvFactor);
}
}
}
}
MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { // Exception (e.g. disk i/o error) occurred when DirectWrite tried to use // the font resource; possibly a failing drive or similar hardware issue. // Mark the font as invalid, and wipe the fontEntry's charmap so that font // selection will skip it; we'll use a fallback font instead.
mIsValid = false;
GetFontEntry()->mCharacterMap = new gfxCharacterMap();
GetFontEntry()->mShmemCharacterMap = nullptr;
gfxCriticalError() << "Exception occurred measuring glyph width for "
<< GetFontEntry()->Name().get();
} return 0.0;
}
bool gfxDWriteFont::GetGlyphBounds(uint16_t aGID, gfxRect* aBounds, bool aTight) {
MOZ_SEH_TRY {
DWRITE_GLYPH_METRICS m;
HRESULT hr = mFontFace->GetDesignGlyphMetrics(&aGID, 1, &m, FALSE); if (FAILED(hr)) { returnfalse;
}
gfxRect bounds(m.leftSideBearing, m.topSideBearing - m.verticalOriginY,
m.advanceWidth - m.leftSideBearing - m.rightSideBearing,
m.advanceHeight - m.topSideBearing - m.bottomSideBearing);
bounds.Scale(mFUnitsConvFactor); // GetDesignGlyphMetrics returns 'ideal' glyph metrics, we need to pad to // account for antialiasing. if (!aTight && !aBounds->IsEmpty()) {
bounds.Inflate(1.0, 0.0);
}
*aBounds = bounds; returntrue;
}
MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { // Exception (e.g. disk i/o error) occurred when DirectWrite tried to use // the font resource; possibly a failing drive or similar hardware issue. // Mark the font as invalid, and wipe the fontEntry's charmap so that font // selection will skip it; we'll use a fallback font instead.
mIsValid = false;
GetFontEntry()->mCharacterMap = new gfxCharacterMap();
GetFontEntry()->mShmemCharacterMap = nullptr;
gfxCriticalError() << "Exception occurred measuring glyph bounds for "
<< GetFontEntry()->Name().get();
} returnfalse;
}
bool gfxDWriteFont::ShouldRoundXOffset(cairo_t* aCairo) const { // show_glyphs is implemented on the font and so is used for all Cairo // surface types; however, it may pixel-snap depending on the dwrite // rendering mode return GetMeasuringMode() != DWRITE_MEASURING_MODE_NATURAL;
}
¤ Dauer der Verarbeitung: 0.16 Sekunden
(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.