Bug 1600470 - Reduce the emboldening strength used for synthetic-bold faces with FreeType. r=lsalzman
☠☠ backed out by 79957874d3a7 ☠ ☠
authorJonathan Kew <jkew@mozilla.com>
Mon, 16 Dec 2019 14:40:21 +0000
changeset 507261 bf28a7e8a8a462ad596746232ab743dd892aa7b3
parent 507260 3c2a1cf616b418feb4fa8f056aa0573671f7e06c
child 507262 ec0c794588d439e229a7f3f397872390e4163ec8
push id36924
push userccoroiu@mozilla.com
push dateTue, 17 Dec 2019 04:13:53 +0000
treeherdermozilla-central@7bebdc108aa3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerslsalzman
bugs1600470
milestone73.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1600470 - Reduce the emboldening strength used for synthetic-bold faces with FreeType. r=lsalzman Differential Revision: https://phabricator.services.mozilla.com/D57246
gfx/2d/Factory.cpp
gfx/skia/generate_mozbuild.py
gfx/skia/skia/src/ports/SkFontHost_cairo.cpp
gfx/thebes/gfxFT2FontBase.cpp
gfx/wr/webrender/src/platform/unix/font.rs
layout/reftests/css-break/reftest.list
layout/reftests/text/synthetic-bold-metrics-01-notref.html
layout/reftests/text/synthetic-bold-metrics-01.html
--- a/gfx/2d/Factory.cpp
+++ b/gfx/2d/Factory.cpp
@@ -60,16 +60,18 @@
 
 #include "Logging.h"
 
 #include "mozilla/CheckedInt.h"
 
 #ifdef MOZ_ENABLE_FREETYPE
 #  include "ft2build.h"
 #  include FT_FREETYPE_H
+#  include FT_OUTLINE_H
+#  include FT_SYNTHESIS_H
 #endif
 #include "MainThreadUtils.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/StaticPrefs_gfx.h"
 
 #if defined(MOZ_LOGGING)
 GFX2D_API mozilla::LogModule* GetGFX2DLog() {
   static mozilla::LazyLogModule sLog("gfx2d");
@@ -190,16 +192,50 @@ FT_Error mozilla_LoadFTGlyph(FT_Face aFa
 
 void mozilla_LockFTLibrary(FT_Library aFTLibrary) {
   mozilla::gfx::Factory::LockFTLibrary(aFTLibrary);
 }
 
 void mozilla_UnlockFTLibrary(FT_Library aFTLibrary) {
   mozilla::gfx::Factory::UnlockFTLibrary(aFTLibrary);
 }
+
+// Custom version of FT_GlyphSlot_Embolden to be less aggressive with outline
+// fonts than the default implementation in FreeType.
+void mozilla_GlyphSlot_Embolden_Less(FT_GlyphSlot slot) {
+  if (!slot) {
+    return;
+  }
+  if (slot->format != FT_GLYPH_FORMAT_OUTLINE) {
+    // For non-outline glyphs, just fall back to FreeType's function.
+    FT_GlyphSlot_Embolden(slot);
+    return;
+  }
+
+  FT_Face face = slot->face;
+
+  // FT_GlyphSlot_Embolden uses a divisor of 24 here; we'll be only half as
+  // bold.
+  FT_Pos strength =
+      FT_MulFix(face->units_per_EM, face->size->metrics.y_scale) / 48;
+  FT_Outline_Embolden(&slot->outline, strength);
+
+  // Adjust metrics to suit the fattened glyph.
+  if (slot->advance.x) {
+    slot->advance.x += strength;
+  }
+  if (slot->advance.y) {
+    slot->advance.y += strength;
+  }
+  slot->metrics.width += strength;
+  slot->metrics.height += strength;
+  slot->metrics.horiAdvance += strength;
+  slot->metrics.vertAdvance += strength;
+  slot->metrics.horiBearingY += strength;
+}
 }
 #endif
 
 namespace mozilla {
 namespace gfx {
 
 #ifdef MOZ_ENABLE_FREETYPE
 FT_Library Factory::mFTLibrary = nullptr;
--- a/gfx/skia/generate_mozbuild.py
+++ b/gfx/skia/generate_mozbuild.py
@@ -67,16 +67,20 @@ elif CONFIG['CPU_ARCH'] == 'aarch64' and
 DEFINES['SKIA_IMPLEMENTATION'] = 1
 
 if CONFIG['MOZ_ENABLE_SKIA_PDF_SFNTLY']:
     DEFINES['SK_PDF_USE_SFNTLY'] = 1
 
 if CONFIG['MOZ_TREE_FREETYPE']:
     DEFINES['SK_CAN_USE_DLOPEN'] = 0
 
+# Reduce strength of synthetic-emboldening used in the freetype backend
+# (see bug 1600470).
+DEFINES['SK_OUTLINE_EMBOLDEN_DIVISOR'] = 48
+
 # Suppress warnings in third-party code.
 CXXFLAGS += [
     '-Wno-deprecated-declarations',
     '-Wno-overloaded-virtual',
     '-Wno-shadow',
     '-Wno-sign-compare',
     '-Wno-unreachable-code',
     '-Wno-unused-function',
--- a/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp
+++ b/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp
@@ -53,39 +53,37 @@ typedef enum FT_LcdFilter_
 #endif
 
 #ifndef SK_FONTHOST_CAIRO_STANDALONE
 #define SK_FONTHOST_CAIRO_STANDALONE 1
 #endif
 
 static bool gFontHintingEnabled = true;
 static FT_Error (*gSetLcdFilter)(FT_Library, FT_LcdFilter) = nullptr;
-static void (*gGlyphSlotEmbolden)(FT_GlyphSlot) = nullptr;
 
 extern "C"
 {
     void mozilla_LockFTLibrary(FT_Library aLibrary);
     void mozilla_UnlockFTLibrary(FT_Library aLibrary);
     void mozilla_AddRefSharedFTFace(void* aContext);
     void mozilla_ReleaseSharedFTFace(void* aContext, void* aOwner);
     void mozilla_ForgetSharedFTFaceLockOwner(void* aContext, void* aOwner);
     int mozilla_LockSharedFTFace(void* aContext, void* aOwner);
     void mozilla_UnlockSharedFTFace(void* aContext);
     FT_Error mozilla_LoadFTGlyph(FT_Face aFace, uint32_t aGlyphIndex, int32_t aFlags);
+    void mozilla_GlyphSlot_Embolden_Less(FT_GlyphSlot slot);
 }
 
 void SkInitCairoFT(bool fontHintingEnabled)
 {
     gFontHintingEnabled = fontHintingEnabled;
 #if SK_CAN_USE_DLOPEN
     gSetLcdFilter = (FT_Error (*)(FT_Library, FT_LcdFilter))dlsym(RTLD_DEFAULT, "FT_Library_SetLcdFilter");
-    gGlyphSlotEmbolden = (void (*)(FT_GlyphSlot))dlsym(RTLD_DEFAULT, "FT_GlyphSlot_Embolden");
 #else
     gSetLcdFilter = &FT_Library_SetLcdFilter;
-    gGlyphSlotEmbolden = &FT_GlyphSlot_Embolden;
 #endif
     // FT_Library_SetLcdFilter may be provided but have no effect if FreeType
     // is built without FT_CONFIG_OPTION_SUBPIXEL_RENDERING.
     if (gSetLcdFilter &&
         gSetLcdFilter(nullptr, FT_LCD_FILTER_NONE) == FT_Err_Unimplemented_Feature) {
         gSetLcdFilter = nullptr;
     }
 }
@@ -481,19 +479,19 @@ unsigned SkScalerContext_CairoFT::genera
 bool SkScalerContext_CairoFT::generateAdvance(SkGlyph* glyph)
 {
     generateMetrics(glyph);
     return !glyph->isEmpty();
 }
 
 void SkScalerContext_CairoFT::prepareGlyph(FT_GlyphSlot glyph)
 {
-    if (fRec.fFlags & SkScalerContext::kEmbolden_Flag &&
-        gGlyphSlotEmbolden) {
-        gGlyphSlotEmbolden(glyph);
+    if (fRec.fFlags & SkScalerContext::kEmbolden_Flag) {
+        // Not FT_GlyphSlot_Embolden because we want a less extreme effect.
+        mozilla_GlyphSlot_Embolden_Less(glyph);
     }
 }
 
 void SkScalerContext_CairoFT::generateMetrics(SkGlyph* glyph)
 {
     glyph->fMaskFormat = fRec.fMaskFormat;
 
     glyph->zeroMetrics();
--- a/gfx/thebes/gfxFT2FontBase.cpp
+++ b/gfx/thebes/gfxFT2FontBase.cpp
@@ -495,16 +495,26 @@ bool gfxFT2FontBase::ShouldRoundXOffset(
                    gfx_text_subpixel_position_force_enabled_AtStartup()));
 }
 
 FT_Vector gfxFT2FontBase::GetEmboldenStrength(FT_Face aFace) {
   FT_Vector strength = {0, 0};
   if (!mEmbolden) {
     return strength;
   }
+
+  // If it's an outline glyph, we'll be using GlyphSlot_Embolden_Less,
+  // so we need to match its strength here.
+  if (aFace->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
+    strength.x =
+        FT_MulFix(aFace->units_per_EM, aFace->size->metrics.y_scale) / 48;
+    strength.y = strength.x;
+    return strength;
+  }
+
   // This is the embolden "strength" used by FT_GlyphSlot_Embolden.
   strength.x =
       FT_MulFix(aFace->units_per_EM, aFace->size->metrics.y_scale) / 24;
   strength.y = strength.x;
   if (aFace->glyph->format == FT_GLYPH_FORMAT_BITMAP) {
     strength.x &= -64;
     if (!strength.x) {
       strength.x = 64;
--- a/gfx/wr/webrender/src/platform/unix/font.rs
+++ b/gfx/wr/webrender/src/platform/unix/font.rs
@@ -101,17 +101,17 @@ macro_rules! ft_dyn_fn {
     ($($proto:tt)+) => { extern "C" { fn $($proto)+; } }
 }
 
 ft_dyn_fn!(FT_Get_MM_Var(face: FT_Face, desc: *mut *mut FT_MM_Var) -> FT_Error);
 ft_dyn_fn!(FT_Done_MM_Var(library: FT_Library, desc: *mut FT_MM_Var) -> FT_Error);
 ft_dyn_fn!(FT_Set_Var_Design_Coordinates(face: FT_Face, num_vals: FT_UInt, vals: *mut FT_Fixed) -> FT_Error);
 
 extern "C" {
-    fn FT_GlyphSlot_Embolden(slot: FT_GlyphSlot);
+    fn mozilla_GlyphSlot_Embolden_Less(slot: FT_GlyphSlot);
 }
 
 enum FontFile {
     Pathname(CString),
     Data(Arc<Vec<u8>>),
 }
 
 struct FontFace {
@@ -490,17 +490,17 @@ impl FontContext {
             );
             return None;
         }
 
         let slot = unsafe { (*face).glyph };
         assert!(slot != ptr::null_mut());
 
         if font.flags.contains(FontInstanceFlags::SYNTHETIC_BOLD) {
-            unsafe { FT_GlyphSlot_Embolden(slot) };
+            unsafe { mozilla_GlyphSlot_Embolden_Less(slot) };
         }
 
         let format = unsafe { (*slot).format };
         match format {
             FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => {
                 let y_size = unsafe { (*(*(*slot).face).size).metrics.y_ppem };
                 Some((slot, req_size as f32 / y_size as f32))
             }
--- a/layout/reftests/css-break/reftest.list
+++ b/layout/reftests/css-break/reftest.list
@@ -1,11 +1,11 @@
 == box-decoration-break-1.html box-decoration-break-1-ref.html
 fuzzy(0-1,0-20) fuzzy-if(skiaContent,0-1,0-700) == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1-ref.html
-skip-if(verify) fuzzy(0-45,0-460) fuzzy-if(skiaContent,0-57,0-439) fuzzy-if(Android,0-57,0-1330) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == box-decoration-break-with-outset-box-shadow-1.html box-decoration-break-with-outset-box-shadow-1-ref.html # Bug 1386543, bug 1392106
+skip-if(verify) fuzzy(0-45,0-460) fuzzy-if(skiaContent,0-57,0-439) fuzzy-if(Android,0-70,0-1330) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == box-decoration-break-with-outset-box-shadow-1.html box-decoration-break-with-outset-box-shadow-1-ref.html # Bug 1386543, bug 1392106
 random-if(!gtkWidget||webrender) == box-decoration-break-border-image.html box-decoration-break-border-image-ref.html
 == box-decoration-break-block-border-padding.html box-decoration-break-block-border-padding-ref.html
 == box-decoration-break-block-margin.html box-decoration-break-block-margin-ref.html
 fuzzy-if(!Android,0-1,0-62) fuzzy-if(Android,0-8,0-6627) random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == box-decoration-break-first-letter.html box-decoration-break-first-letter-ref.html #Bug 1313773 # Bug 1392106
 == box-decoration-break-with-bidi.html box-decoration-break-with-bidi-ref.html
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == box-decoration-break-bug-1235152.html box-decoration-break-bug-1235152-ref.html # Bug 1392106
 random-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == box-decoration-break-bug-1249913.html box-decoration-break-bug-1249913-ref.html # Bug 1392106
 == vertical-wm-001.html vertical-wm-001-ref.html
--- a/layout/reftests/text/synthetic-bold-metrics-01-notref.html
+++ b/layout/reftests/text/synthetic-bold-metrics-01-notref.html
@@ -3,17 +3,17 @@
 <head>
 <style type="text/css">
 @font-face {
   font-family: dejavu;
   src: url(../fonts/dejavu-sans/DejaVuSans.ttf);
 }
 
 p {
-  font-family: dejavu; /* family with only a single weight */
+  font: 32px dejavu; /* family with only a single weight */
 }
 
 .test {
   color: white; /* hide the text, we're only comparing metrics */
 }
 </style>
 </head>
 <body>
--- a/layout/reftests/text/synthetic-bold-metrics-01.html
+++ b/layout/reftests/text/synthetic-bold-metrics-01.html
@@ -3,17 +3,17 @@
 <head>
 <style type="text/css">
 @font-face {
   font-family: dejavu;
   src: url(../fonts/dejavu-sans/DejaVuSans.ttf);
 }
 
 p {
-  font-family: dejavu; /* family with only a single weight */
+  font: 32px dejavu; /* family with only a single weight */
 }
 
 .test {
   color: white; /* hide the text, we're only comparing metrics */
   font-weight: bold; /* synthetic bold will be used */
 }
 </style>
 </head>