1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/thebes/gfxGDIFont.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,584 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "gfxGDIFont.h" 1.10 + 1.11 +#include "mozilla/MemoryReporting.h" 1.12 +#include "mozilla/WindowsVersion.h" 1.13 + 1.14 +#include "gfxGDIShaper.h" 1.15 +#include "gfxUniscribeShaper.h" 1.16 +#include "gfxHarfBuzzShaper.h" 1.17 +#include <algorithm> 1.18 +#include "gfxGraphiteShaper.h" 1.19 +#include "gfxWindowsPlatform.h" 1.20 +#include "gfxContext.h" 1.21 +#include "mozilla/Preferences.h" 1.22 +#include "nsUnicodeProperties.h" 1.23 +#include "gfxFontConstants.h" 1.24 + 1.25 +#include "cairo-win32.h" 1.26 + 1.27 +#define ROUND(x) floor((x) + 0.5) 1.28 + 1.29 +using namespace mozilla; 1.30 +using namespace mozilla::unicode; 1.31 + 1.32 +static inline cairo_antialias_t 1.33 +GetCairoAntialiasOption(gfxFont::AntialiasOption anAntialiasOption) 1.34 +{ 1.35 + switch (anAntialiasOption) { 1.36 + default: 1.37 + case gfxFont::kAntialiasDefault: 1.38 + return CAIRO_ANTIALIAS_DEFAULT; 1.39 + case gfxFont::kAntialiasNone: 1.40 + return CAIRO_ANTIALIAS_NONE; 1.41 + case gfxFont::kAntialiasGrayscale: 1.42 + return CAIRO_ANTIALIAS_GRAY; 1.43 + case gfxFont::kAntialiasSubpixel: 1.44 + return CAIRO_ANTIALIAS_SUBPIXEL; 1.45 + } 1.46 +} 1.47 + 1.48 +gfxGDIFont::gfxGDIFont(GDIFontEntry *aFontEntry, 1.49 + const gfxFontStyle *aFontStyle, 1.50 + bool aNeedsBold, 1.51 + AntialiasOption anAAOption) 1.52 + : gfxFont(aFontEntry, aFontStyle, anAAOption), 1.53 + mFont(nullptr), 1.54 + mFontFace(nullptr), 1.55 + mMetrics(nullptr), 1.56 + mSpaceGlyph(0), 1.57 + mNeedsBold(aNeedsBold) 1.58 +{ 1.59 + if (FontCanSupportGraphite()) { 1.60 + mGraphiteShaper = new gfxGraphiteShaper(this); 1.61 + } 1.62 + if (FontCanSupportHarfBuzz()) { 1.63 + mHarfBuzzShaper = new gfxHarfBuzzShaper(this); 1.64 + } 1.65 +} 1.66 + 1.67 +gfxGDIFont::~gfxGDIFont() 1.68 +{ 1.69 + if (mScaledFont) { 1.70 + cairo_scaled_font_destroy(mScaledFont); 1.71 + } 1.72 + if (mFontFace) { 1.73 + cairo_font_face_destroy(mFontFace); 1.74 + } 1.75 + if (mFont) { 1.76 + ::DeleteObject(mFont); 1.77 + } 1.78 + delete mMetrics; 1.79 +} 1.80 + 1.81 +void 1.82 +gfxGDIFont::CreatePlatformShaper() 1.83 +{ 1.84 + mPlatformShaper = new gfxGDIShaper(this); 1.85 +} 1.86 + 1.87 +gfxFont* 1.88 +gfxGDIFont::CopyWithAntialiasOption(AntialiasOption anAAOption) 1.89 +{ 1.90 + return new gfxGDIFont(static_cast<GDIFontEntry*>(mFontEntry.get()), 1.91 + &mStyle, mNeedsBold, anAAOption); 1.92 +} 1.93 + 1.94 +static bool 1.95 +UseUniscribe(gfxShapedText *aShapedText, 1.96 + char16ptr_t aText, 1.97 + uint32_t aLength) 1.98 +{ 1.99 + uint32_t flags = aShapedText->Flags(); 1.100 + bool useGDI; 1.101 + 1.102 + bool isXP = !IsVistaOrLater(); 1.103 + 1.104 + // bug 561304 - Uniscribe bug produces bad positioning at certain 1.105 + // font sizes on XP, so default to GDI on XP using logic of 3.6 1.106 + 1.107 + useGDI = isXP && 1.108 + (flags & 1.109 + (gfxTextRunFactory::TEXT_OPTIMIZE_SPEED | 1.110 + gfxTextRunFactory::TEXT_IS_RTL) 1.111 + ) == gfxTextRunFactory::TEXT_OPTIMIZE_SPEED; 1.112 + 1.113 + return !useGDI || 1.114 + ScriptIsComplex(aText, aLength, SIC_COMPLEX) == S_OK; 1.115 +} 1.116 + 1.117 +bool 1.118 +gfxGDIFont::ShapeText(gfxContext *aContext, 1.119 + const char16_t *aText, 1.120 + uint32_t aOffset, 1.121 + uint32_t aLength, 1.122 + int32_t aScript, 1.123 + gfxShapedText *aShapedText, 1.124 + bool aPreferPlatformShaping) 1.125 +{ 1.126 + if (!mMetrics) { 1.127 + Initialize(); 1.128 + } 1.129 + if (!mIsValid) { 1.130 + NS_WARNING("invalid font! expect incorrect text rendering"); 1.131 + return false; 1.132 + } 1.133 + 1.134 + bool ok = false; 1.135 + 1.136 + // Ensure the cairo font is set up, so there's no risk it'll fall back to 1.137 + // creating a "toy" font internally (see bug 544617). 1.138 + // We must check that this succeeded, otherwise we risk cairo creating the 1.139 + // wrong kind of font internally as a fallback (bug 744480). 1.140 + if (!SetupCairoFont(aContext)) { 1.141 + return false; 1.142 + } 1.143 + 1.144 + if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) { 1.145 + ok = mGraphiteShaper->ShapeText(aContext, aText, 1.146 + aOffset, aLength, 1.147 + aScript, aShapedText); 1.148 + } 1.149 + 1.150 + if (!ok && mHarfBuzzShaper) { 1.151 + if (gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aScript) || 1.152 + (!IsVistaOrLater() && 1.153 + ScriptShapingType(aScript) == SHAPING_INDIC && 1.154 + !Preferences::GetBool("gfx.font_rendering.winxp-indic-uniscribe", 1.155 + false))) { 1.156 + ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength, 1.157 + aScript, aShapedText); 1.158 + } 1.159 + } 1.160 + 1.161 + if (!ok) { 1.162 + GDIFontEntry *fe = static_cast<GDIFontEntry*>(GetFontEntry()); 1.163 + bool preferUniscribe = 1.164 + (!fe->IsTrueType() || fe->IsSymbolFont()) && !fe->mForceGDI; 1.165 + 1.166 + if (preferUniscribe || UseUniscribe(aShapedText, aText, aLength)) { 1.167 + // first try Uniscribe 1.168 + if (!mUniscribeShaper) { 1.169 + mUniscribeShaper = new gfxUniscribeShaper(this); 1.170 + } 1.171 + 1.172 + ok = mUniscribeShaper->ShapeText(aContext, aText, aOffset, aLength, 1.173 + aScript, aShapedText); 1.174 + if (!ok) { 1.175 + // fallback to GDI shaping 1.176 + if (!mPlatformShaper) { 1.177 + CreatePlatformShaper(); 1.178 + } 1.179 + 1.180 + ok = mPlatformShaper->ShapeText(aContext, aText, aOffset, 1.181 + aLength, aScript, aShapedText); 1.182 + } 1.183 + } else { 1.184 + // first use GDI 1.185 + if (!mPlatformShaper) { 1.186 + CreatePlatformShaper(); 1.187 + } 1.188 + 1.189 + ok = mPlatformShaper->ShapeText(aContext, aText, aOffset, aLength, 1.190 + aScript, aShapedText); 1.191 + if (!ok) { 1.192 + // try Uniscribe if GDI failed 1.193 + if (!mUniscribeShaper) { 1.194 + mUniscribeShaper = new gfxUniscribeShaper(this); 1.195 + } 1.196 + 1.197 + // use Uniscribe shaping 1.198 + ok = mUniscribeShaper->ShapeText(aContext, aText, 1.199 + aOffset, aLength, 1.200 + aScript, aShapedText); 1.201 + } 1.202 + } 1.203 + 1.204 +#if DEBUG 1.205 + if (!ok) { 1.206 + NS_ConvertUTF16toUTF8 name(GetName()); 1.207 + char msg[256]; 1.208 + 1.209 + sprintf(msg, 1.210 + "text shaping with both uniscribe and GDI failed for" 1.211 + " font: %s", 1.212 + name.get()); 1.213 + NS_WARNING(msg); 1.214 + } 1.215 +#endif 1.216 + } 1.217 + 1.218 + PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText); 1.219 + 1.220 + return ok; 1.221 +} 1.222 + 1.223 +const gfxFont::Metrics& 1.224 +gfxGDIFont::GetMetrics() 1.225 +{ 1.226 + if (!mMetrics) { 1.227 + Initialize(); 1.228 + } 1.229 + return *mMetrics; 1.230 +} 1.231 + 1.232 +uint32_t 1.233 +gfxGDIFont::GetSpaceGlyph() 1.234 +{ 1.235 + if (!mMetrics) { 1.236 + Initialize(); 1.237 + } 1.238 + return mSpaceGlyph; 1.239 +} 1.240 + 1.241 +bool 1.242 +gfxGDIFont::SetupCairoFont(gfxContext *aContext) 1.243 +{ 1.244 + if (!mMetrics) { 1.245 + Initialize(); 1.246 + } 1.247 + if (!mScaledFont || 1.248 + cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) { 1.249 + // Don't cairo_set_scaled_font as that would propagate the error to 1.250 + // the cairo_t, precluding any further drawing. 1.251 + return false; 1.252 + } 1.253 + cairo_set_scaled_font(aContext->GetCairo(), mScaledFont); 1.254 + return true; 1.255 +} 1.256 + 1.257 +gfxFont::RunMetrics 1.258 +gfxGDIFont::Measure(gfxTextRun *aTextRun, 1.259 + uint32_t aStart, uint32_t aEnd, 1.260 + BoundingBoxType aBoundingBoxType, 1.261 + gfxContext *aRefContext, 1.262 + Spacing *aSpacing) 1.263 +{ 1.264 + gfxFont::RunMetrics metrics = 1.265 + gfxFont::Measure(aTextRun, aStart, aEnd, 1.266 + aBoundingBoxType, aRefContext, aSpacing); 1.267 + 1.268 + // if aBoundingBoxType is LOOSE_INK_EXTENTS 1.269 + // and the underlying cairo font may be antialiased, 1.270 + // we can't trust Windows to have considered all the pixels 1.271 + // so we need to add "padding" to the bounds. 1.272 + // (see bugs 475968, 439831, compare also bug 445087) 1.273 + if (aBoundingBoxType == LOOSE_INK_EXTENTS && 1.274 + mAntialiasOption != kAntialiasNone && 1.275 + metrics.mBoundingBox.width > 0) { 1.276 + metrics.mBoundingBox.x -= aTextRun->GetAppUnitsPerDevUnit(); 1.277 + metrics.mBoundingBox.width += aTextRun->GetAppUnitsPerDevUnit() * 3; 1.278 + } 1.279 + 1.280 + return metrics; 1.281 +} 1.282 + 1.283 +#define OBLIQUE_SKEW_FACTOR 0.3 1.284 + 1.285 +void 1.286 +gfxGDIFont::Initialize() 1.287 +{ 1.288 + NS_ASSERTION(!mMetrics, "re-creating metrics? this will leak"); 1.289 + 1.290 + LOGFONTW logFont; 1.291 + 1.292 + // Figure out if we want to do synthetic oblique styling. 1.293 + GDIFontEntry* fe = static_cast<GDIFontEntry*>(GetFontEntry()); 1.294 + bool wantFakeItalic = 1.295 + (mStyle.style & (NS_FONT_STYLE_ITALIC | NS_FONT_STYLE_OBLIQUE)) && 1.296 + !fe->IsItalic(); 1.297 + 1.298 + // If the font's family has an actual italic face (but font matching 1.299 + // didn't choose it), we have to use a cairo transform instead of asking 1.300 + // GDI to italicize, because that would use a different face and result 1.301 + // in a possible glyph ID mismatch between shaping and rendering. 1.302 + // 1.303 + // We use the mFamilyHasItalicFace flag in the entry in case of user fonts, 1.304 + // where the *CSS* family may not know about italic faces that are present 1.305 + // in the *GDI* family, and which GDI would use if we asked it to perform 1.306 + // the "italicization". 1.307 + bool useCairoFakeItalic = wantFakeItalic && fe->mFamilyHasItalicFace; 1.308 + 1.309 + if (mAdjustedSize == 0.0) { 1.310 + mAdjustedSize = mStyle.size; 1.311 + if (mStyle.sizeAdjust != 0.0 && mAdjustedSize > 0.0) { 1.312 + // to implement font-size-adjust, we first create the "unadjusted" font 1.313 + FillLogFont(logFont, mAdjustedSize, 1.314 + wantFakeItalic && !useCairoFakeItalic); 1.315 + mFont = ::CreateFontIndirectW(&logFont); 1.316 + 1.317 + // initialize its metrics so we can calculate size adjustment 1.318 + Initialize(); 1.319 + 1.320 + // calculate the properly adjusted size, and then proceed 1.321 + // to recreate mFont and recalculate metrics 1.322 + gfxFloat aspect = mMetrics->xHeight / mMetrics->emHeight; 1.323 + mAdjustedSize = mStyle.GetAdjustedSize(aspect); 1.324 + 1.325 + // delete the temporary font and metrics 1.326 + ::DeleteObject(mFont); 1.327 + mFont = nullptr; 1.328 + delete mMetrics; 1.329 + mMetrics = nullptr; 1.330 + } 1.331 + } 1.332 + 1.333 + // (bug 724231) for local user fonts, we don't use GDI's synthetic bold, 1.334 + // as it could lead to a different, incompatible face being used 1.335 + // but instead do our own multi-striking 1.336 + if (mNeedsBold && GetFontEntry()->IsLocalUserFont()) { 1.337 + mApplySyntheticBold = true; 1.338 + } 1.339 + 1.340 + // this may end up being zero 1.341 + mAdjustedSize = ROUND(mAdjustedSize); 1.342 + FillLogFont(logFont, mAdjustedSize, wantFakeItalic && !useCairoFakeItalic); 1.343 + mFont = ::CreateFontIndirectW(&logFont); 1.344 + 1.345 + mMetrics = new gfxFont::Metrics; 1.346 + ::memset(mMetrics, 0, sizeof(*mMetrics)); 1.347 + 1.348 + AutoDC dc; 1.349 + SetGraphicsMode(dc.GetDC(), GM_ADVANCED); 1.350 + AutoSelectFont selectFont(dc.GetDC(), mFont); 1.351 + 1.352 + // Get font metrics if size > 0 1.353 + if (mAdjustedSize > 0.0) { 1.354 + 1.355 + OUTLINETEXTMETRIC oMetrics; 1.356 + TEXTMETRIC& metrics = oMetrics.otmTextMetrics; 1.357 + 1.358 + if (0 < GetOutlineTextMetrics(dc.GetDC(), sizeof(oMetrics), &oMetrics)) { 1.359 + mMetrics->superscriptOffset = (double)oMetrics.otmptSuperscriptOffset.y; 1.360 + // Some fonts have wrong sign on their subscript offset, bug 410917. 1.361 + mMetrics->subscriptOffset = fabs((double)oMetrics.otmptSubscriptOffset.y); 1.362 + mMetrics->strikeoutSize = (double)oMetrics.otmsStrikeoutSize; 1.363 + mMetrics->strikeoutOffset = (double)oMetrics.otmsStrikeoutPosition; 1.364 + mMetrics->underlineSize = (double)oMetrics.otmsUnderscoreSize; 1.365 + mMetrics->underlineOffset = (double)oMetrics.otmsUnderscorePosition; 1.366 + 1.367 + const MAT2 kIdentityMatrix = { {0, 1}, {0, 0}, {0, 0}, {0, 1} }; 1.368 + GLYPHMETRICS gm; 1.369 + DWORD len = GetGlyphOutlineW(dc.GetDC(), char16_t('x'), GGO_METRICS, &gm, 0, nullptr, &kIdentityMatrix); 1.370 + if (len == GDI_ERROR || gm.gmptGlyphOrigin.y <= 0) { 1.371 + // 56% of ascent, best guess for true type 1.372 + mMetrics->xHeight = 1.373 + ROUND((double)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR); 1.374 + } else { 1.375 + mMetrics->xHeight = gm.gmptGlyphOrigin.y; 1.376 + } 1.377 + mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading; 1.378 + gfxFloat typEmHeight = (double)oMetrics.otmAscent - (double)oMetrics.otmDescent; 1.379 + mMetrics->emAscent = ROUND(mMetrics->emHeight * (double)oMetrics.otmAscent / typEmHeight); 1.380 + mMetrics->emDescent = mMetrics->emHeight - mMetrics->emAscent; 1.381 + if (oMetrics.otmEMSquare > 0) { 1.382 + mFUnitsConvFactor = float(mAdjustedSize / oMetrics.otmEMSquare); 1.383 + } 1.384 + } else { 1.385 + // Make a best-effort guess at extended metrics 1.386 + // this is based on general typographic guidelines 1.387 + 1.388 + // GetTextMetrics can fail if the font file has been removed 1.389 + // or corrupted recently. 1.390 + BOOL result = GetTextMetrics(dc.GetDC(), &metrics); 1.391 + if (!result) { 1.392 + NS_WARNING("Missing or corrupt font data, fasten your seatbelt"); 1.393 + mIsValid = false; 1.394 + memset(mMetrics, 0, sizeof(*mMetrics)); 1.395 + return; 1.396 + } 1.397 + 1.398 + mMetrics->xHeight = 1.399 + ROUND((float)metrics.tmAscent * DEFAULT_XHEIGHT_FACTOR); 1.400 + mMetrics->superscriptOffset = mMetrics->xHeight; 1.401 + mMetrics->subscriptOffset = mMetrics->xHeight; 1.402 + mMetrics->strikeoutSize = 1; 1.403 + mMetrics->strikeoutOffset = ROUND(mMetrics->xHeight * 0.5f); // 50% of xHeight 1.404 + mMetrics->underlineSize = 1; 1.405 + mMetrics->underlineOffset = -ROUND((float)metrics.tmDescent * 0.30f); // 30% of descent 1.406 + mMetrics->emHeight = metrics.tmHeight - metrics.tmInternalLeading; 1.407 + mMetrics->emAscent = metrics.tmAscent - metrics.tmInternalLeading; 1.408 + mMetrics->emDescent = metrics.tmDescent; 1.409 + } 1.410 + 1.411 + mMetrics->internalLeading = metrics.tmInternalLeading; 1.412 + mMetrics->externalLeading = metrics.tmExternalLeading; 1.413 + mMetrics->maxHeight = metrics.tmHeight; 1.414 + mMetrics->maxAscent = metrics.tmAscent; 1.415 + mMetrics->maxDescent = metrics.tmDescent; 1.416 + mMetrics->maxAdvance = metrics.tmMaxCharWidth; 1.417 + mMetrics->aveCharWidth = std::max<gfxFloat>(1, metrics.tmAveCharWidth); 1.418 + // The font is monospace when TMPF_FIXED_PITCH is *not* set! 1.419 + // See http://msdn2.microsoft.com/en-us/library/ms534202(VS.85).aspx 1.420 + if (!(metrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) { 1.421 + mMetrics->maxAdvance = mMetrics->aveCharWidth; 1.422 + } 1.423 + 1.424 + // Cache the width of a single space. 1.425 + SIZE size; 1.426 + GetTextExtentPoint32W(dc.GetDC(), L" ", 1, &size); 1.427 + mMetrics->spaceWidth = ROUND(size.cx); 1.428 + 1.429 + // Cache the width of digit zero. 1.430 + // XXX MSDN (http://msdn.microsoft.com/en-us/library/ms534223.aspx) 1.431 + // does not say what the failure modes for GetTextExtentPoint32 are - 1.432 + // is it safe to assume it will fail iff the font has no '0'? 1.433 + if (GetTextExtentPoint32W(dc.GetDC(), L"0", 1, &size)) { 1.434 + mMetrics->zeroOrAveCharWidth = ROUND(size.cx); 1.435 + } else { 1.436 + mMetrics->zeroOrAveCharWidth = mMetrics->aveCharWidth; 1.437 + } 1.438 + 1.439 + WORD glyph; 1.440 + DWORD ret = GetGlyphIndicesW(dc.GetDC(), L" ", 1, &glyph, 1.441 + GGI_MARK_NONEXISTING_GLYPHS); 1.442 + if (ret != GDI_ERROR && glyph != 0xFFFF) { 1.443 + mSpaceGlyph = glyph; 1.444 + } 1.445 + 1.446 + SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont); 1.447 + } 1.448 + 1.449 + if (IsSyntheticBold()) { 1.450 + mMetrics->aveCharWidth += GetSyntheticBoldOffset(); 1.451 + mMetrics->maxAdvance += GetSyntheticBoldOffset(); 1.452 + } 1.453 + 1.454 + mFontFace = cairo_win32_font_face_create_for_logfontw_hfont(&logFont, 1.455 + mFont); 1.456 + 1.457 + cairo_matrix_t sizeMatrix, ctm; 1.458 + cairo_matrix_init_identity(&ctm); 1.459 + cairo_matrix_init_scale(&sizeMatrix, mAdjustedSize, mAdjustedSize); 1.460 + 1.461 + if (useCairoFakeItalic) { 1.462 + // Skew the matrix to do fake italic if it wasn't already applied 1.463 + // via the LOGFONT 1.464 + double skewfactor = OBLIQUE_SKEW_FACTOR; 1.465 + cairo_matrix_t style; 1.466 + cairo_matrix_init(&style, 1.467 + 1, //xx 1.468 + 0, //yx 1.469 + -1 * skewfactor, //xy 1.470 + 1, //yy 1.471 + 0, //x0 1.472 + 0); //y0 1.473 + cairo_matrix_multiply(&sizeMatrix, &sizeMatrix, &style); 1.474 + } 1.475 + 1.476 + cairo_font_options_t *fontOptions = cairo_font_options_create(); 1.477 + if (mAntialiasOption != kAntialiasDefault) { 1.478 + cairo_font_options_set_antialias(fontOptions, 1.479 + GetCairoAntialiasOption(mAntialiasOption)); 1.480 + } 1.481 + mScaledFont = cairo_scaled_font_create(mFontFace, &sizeMatrix, 1.482 + &ctm, fontOptions); 1.483 + cairo_font_options_destroy(fontOptions); 1.484 + 1.485 + if (!mScaledFont || 1.486 + cairo_scaled_font_status(mScaledFont) != CAIRO_STATUS_SUCCESS) { 1.487 +#ifdef DEBUG 1.488 + char warnBuf[1024]; 1.489 + sprintf(warnBuf, "Failed to create scaled font: %s status: %d", 1.490 + NS_ConvertUTF16toUTF8(mFontEntry->Name()).get(), 1.491 + mScaledFont ? cairo_scaled_font_status(mScaledFont) : 0); 1.492 + NS_WARNING(warnBuf); 1.493 +#endif 1.494 + mIsValid = false; 1.495 + } else { 1.496 + mIsValid = true; 1.497 + } 1.498 + 1.499 +#if 0 1.500 + printf("Font: %p (%s) size: %f adjusted size: %f valid: %s\n", this, 1.501 + NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size, mAdjustedSize, (mIsValid ? "yes" : "no")); 1.502 + printf(" emHeight: %f emAscent: %f emDescent: %f\n", mMetrics->emHeight, mMetrics->emAscent, mMetrics->emDescent); 1.503 + printf(" maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics->maxAscent, mMetrics->maxDescent, mMetrics->maxAdvance); 1.504 + printf(" internalLeading: %f externalLeading: %f\n", mMetrics->internalLeading, mMetrics->externalLeading); 1.505 + printf(" spaceWidth: %f aveCharWidth: %f xHeight: %f\n", mMetrics->spaceWidth, mMetrics->aveCharWidth, mMetrics->xHeight); 1.506 + printf(" uOff: %f uSize: %f stOff: %f stSize: %f supOff: %f subOff: %f\n", 1.507 + mMetrics->underlineOffset, mMetrics->underlineSize, mMetrics->strikeoutOffset, mMetrics->strikeoutSize, 1.508 + mMetrics->superscriptOffset, mMetrics->subscriptOffset); 1.509 +#endif 1.510 +} 1.511 + 1.512 +void 1.513 +gfxGDIFont::FillLogFont(LOGFONTW& aLogFont, gfxFloat aSize, 1.514 + bool aUseGDIFakeItalic) 1.515 +{ 1.516 + GDIFontEntry *fe = static_cast<GDIFontEntry*>(GetFontEntry()); 1.517 + 1.518 + uint16_t weight; 1.519 + if (fe->IsUserFont()) { 1.520 + if (fe->IsLocalUserFont()) { 1.521 + // for local user fonts, don't change the original weight 1.522 + // in the entry's logfont, because that could alter the 1.523 + // choice of actual face used (bug 724231) 1.524 + weight = 0; 1.525 + } else { 1.526 + // avoid GDI synthetic bold which occurs when weight 1.527 + // specified is >= font data weight + 200 1.528 + weight = mNeedsBold ? 700 : 200; 1.529 + } 1.530 + } else { 1.531 + weight = mNeedsBold ? 700 : fe->Weight(); 1.532 + } 1.533 + 1.534 + fe->FillLogFont(&aLogFont, weight, aSize, 1.535 + (mAntialiasOption == kAntialiasSubpixel) ? true : false); 1.536 + 1.537 + // If GDI synthetic italic is wanted, force the lfItalic field to true 1.538 + if (aUseGDIFakeItalic) { 1.539 + aLogFont.lfItalic = 1; 1.540 + } 1.541 +} 1.542 + 1.543 +int32_t 1.544 +gfxGDIFont::GetGlyphWidth(gfxContext *aCtx, uint16_t aGID) 1.545 +{ 1.546 + if (!mGlyphWidths) { 1.547 + mGlyphWidths = new nsDataHashtable<nsUint32HashKey,int32_t>(200); 1.548 + } 1.549 + 1.550 + int32_t width; 1.551 + if (mGlyphWidths->Get(aGID, &width)) { 1.552 + return width; 1.553 + } 1.554 + 1.555 + DCFromContext dc(aCtx); 1.556 + AutoSelectFont fs(dc, GetHFONT()); 1.557 + 1.558 + int devWidth; 1.559 + if (GetCharWidthI(dc, aGID, 1, nullptr, &devWidth)) { 1.560 + // ensure width is positive, 16.16 fixed-point value 1.561 + width = (devWidth & 0x7fff) << 16; 1.562 + mGlyphWidths->Put(aGID, width); 1.563 + return width; 1.564 + } 1.565 + 1.566 + return -1; 1.567 +} 1.568 + 1.569 +void 1.570 +gfxGDIFont::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf, 1.571 + FontCacheSizes* aSizes) const 1.572 +{ 1.573 + gfxFont::AddSizeOfExcludingThis(aMallocSizeOf, aSizes); 1.574 + aSizes->mFontInstances += aMallocSizeOf(mMetrics); 1.575 + if (mGlyphWidths) { 1.576 + aSizes->mFontInstances += 1.577 + mGlyphWidths->SizeOfExcludingThis(nullptr, aMallocSizeOf); 1.578 + } 1.579 +} 1.580 + 1.581 +void 1.582 +gfxGDIFont::AddSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf, 1.583 + FontCacheSizes* aSizes) const 1.584 +{ 1.585 + aSizes->mFontInstances += aMallocSizeOf(this); 1.586 + AddSizeOfExcludingThis(aMallocSizeOf, aSizes); 1.587 +}