From d03fa2690fa5bc09693d71b4276a32b03b5e524e Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Tue, 14 Feb 2012 08:24:26 +0000 Subject: [PATCH] bug 724231 - ensure synthetic font styles under GDI are truly synthetic, rather than using a potentially incompatible font face. r=jdaggett --- gfx/thebes/gfxGDIFont.cpp | 57 ++++++++++++++++++++++++++++------- gfx/thebes/gfxGDIFontList.cpp | 30 ++++++++++++------ gfx/thebes/gfxGDIFontList.h | 4 +-- 3 files changed, 69 insertions(+), 22 deletions(-) diff --git a/gfx/thebes/gfxGDIFont.cpp b/gfx/thebes/gfxGDIFont.cpp index 9c7debb09c1..7dc33776cdf 100644 --- a/gfx/thebes/gfxGDIFont.cpp +++ b/gfx/thebes/gfxGDIFont.cpp @@ -229,6 +229,12 @@ gfxGDIFont::ShapeWord(gfxContext *aContext, #endif } + if (ok && IsSyntheticBold()) { + float synBoldOffset = + GetSyntheticBoldOffset() * CalcXScale(aContext); + aShapedWord->AdjustAdvancesForSyntheticBold(synBoldOffset); + } + return ok; } @@ -292,6 +298,8 @@ gfxGDIFont::Measure(gfxTextRun *aTextRun, return metrics; } +#define OBLIQUE_SKEW_FACTOR 0.3 + void gfxGDIFont::Initialize() { @@ -322,6 +330,13 @@ gfxGDIFont::Initialize() } } + // (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); @@ -434,6 +449,11 @@ gfxGDIFont::Initialize() SanitizeMetrics(mMetrics, GetFontEntry()->mIsBadUnderlineFont); } + if (IsSyntheticBold()) { + mMetrics->aveCharWidth += GetSyntheticBoldOffset(); + mMetrics->maxAdvance += GetSyntheticBoldOffset(); + } + mFontFace = cairo_win32_font_face_create_for_logfontw_hfont(&logFont, mFont); @@ -441,6 +461,20 @@ gfxGDIFont::Initialize() cairo_matrix_init_identity(&ctm); cairo_matrix_init_scale(&sizeMatrix, mAdjustedSize, mAdjustedSize); + bool italic = (mStyle.style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)); + if (italic && !mFontEntry->IsItalic()) { + 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, @@ -482,22 +516,23 @@ gfxGDIFont::FillLogFont(LOGFONTW& aLogFont, gfxFloat aSize) { GDIFontEntry *fe = static_cast(GetFontEntry()); - PRUint16 weight = mNeedsBold ? 700 : fe->Weight(); - bool italic = (mStyle.style & (FONT_STYLE_ITALIC | FONT_STYLE_OBLIQUE)); - - // if user font, disable italics/bold if defined to be italics/bold face - // this avoids unwanted synthetic italics/bold - if (fe->mIsUserFont) { - if (fe->IsItalic()) - italic = false; // avoid synthetic italic - if (fe->IsBold() || !mNeedsBold) { + PRUint16 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 = 200; + weight = mNeedsBold ? 700 : 200; } + } else { + weight = mNeedsBold ? 700 : fe->Weight(); } - fe->FillLogFont(&aLogFont, italic, weight, aSize, + fe->FillLogFont(&aLogFont, weight, aSize, (mAntialiasOption == kAntialiasSubpixel) ? true : false); } diff --git a/gfx/thebes/gfxGDIFontList.cpp b/gfx/thebes/gfxGDIFontList.cpp index 18d6f72fecd..4e59285122e 100644 --- a/gfx/thebes/gfxGDIFontList.cpp +++ b/gfx/thebes/gfxGDIFontList.cpp @@ -322,7 +322,7 @@ GDIFontEntry::GetFontTable(PRUint32 aTableTag, } void -GDIFontEntry::FillLogFont(LOGFONTW *aLogFont, bool aItalic, +GDIFontEntry::FillLogFont(LOGFONTW *aLogFont, PRUint16 aWeight, gfxFloat aSize, bool aUseCleartype) { @@ -330,16 +330,28 @@ GDIFontEntry::FillLogFont(LOGFONTW *aLogFont, bool aItalic, aLogFont->lfHeight = (LONG)-ROUND(aSize); - if (aLogFont->lfHeight == 0) + if (aLogFont->lfHeight == 0) { aLogFont->lfHeight = -1; + } - // always force lfItalic if we want it. Font selection code will - // do its best to give us an italic font entry, but if no face exists - // it may give us a regular one based on weight. Windows should - // do fake italic for us in that case. - aLogFont->lfItalic = aItalic; - aLogFont->lfWeight = aWeight; - aLogFont->lfQuality = (aUseCleartype ? CLEARTYPE_QUALITY : DEFAULT_QUALITY); + // If a non-zero weight is passed in, use this to override the original + // weight in the entry's logfont. This is used to control synthetic bolding + // for installed families with no bold face, and for downloaded fonts + // (but NOT for local user fonts, because it could cause a different, + // glyph-incompatible face to be used) + if (aWeight) { + aLogFont->lfWeight = aWeight; + } + + // for non-local() user fonts, we never want to apply italics here; + // if the face is described as italic, we should use it as-is, + // and if it's not, but then the element is styled italic, we'll use + // a cairo transform to create fake italic (oblique) + if (IsUserFont() && !IsLocalUserFont()) { + aLogFont->lfItalic = 0; + } + + aLogFont->lfQuality = (aUseCleartype ? CLEARTYPE_QUALITY : DEFAULT_QUALITY); } #define MISSING_GLYPH 0x1F // glyph index returned for missing characters diff --git a/gfx/thebes/gfxGDIFontList.h b/gfx/thebes/gfxGDIFontList.h index 41372b3d818..320879b3d73 100644 --- a/gfx/thebes/gfxGDIFontList.h +++ b/gfx/thebes/gfxGDIFontList.h @@ -146,8 +146,8 @@ public: virtual bool IsSymbolFont(); - void FillLogFont(LOGFONTW *aLogFont, bool aItalic, - PRUint16 aWeight, gfxFloat aSize, bool aUseCleartype); + void FillLogFont(LOGFONTW *aLogFont, PRUint16 aWeight, gfxFloat aSize, + bool aUseCleartype); static gfxWindowsFontType DetermineFontType(const NEWTEXTMETRICW& metrics, DWORD fontType)