Bug 1297178 - disable explicit subpixel AA when not permitted in DrawTargetCairo::FillGlyphs. r=jrmuizel
authorLee Salzman <lsalzman@mozilla.com>
Fri, 26 Aug 2016 15:28:28 -0400
changeset 352832 3c2b69f54e9b946f35aedbc8be5b2e5bf8066f78
parent 352831 8d266498a9819b5bdd58520936ac73206b237c10
child 352833 926053fe7f066c95192f410947b13bce2920d615
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1297178
milestone51.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 1297178 - disable explicit subpixel AA when not permitted in DrawTargetCairo::FillGlyphs. r=jrmuizel MozReview-Commit-ID: 7VG7837zyh0
gfx/2d/DrawTargetCairo.cpp
gfx/2d/DrawTargetCairo.h
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -596,26 +596,31 @@ NeedIntermediateSurface(const Pattern& a
   return true;
 }
 
 DrawTargetCairo::DrawTargetCairo()
   : mContext(nullptr)
   , mSurface(nullptr)
   , mTransformSingular(false)
   , mLockedBits(nullptr)
+  , mFontOptions(nullptr)
 {
 }
 
 DrawTargetCairo::~DrawTargetCairo()
 {
   cairo_destroy(mContext);
   if (mSurface) {
     cairo_surface_destroy(mSurface);
     mSurface = nullptr;
   }
+  if (mFontOptions) {
+    cairo_font_options_destroy(mFontOptions);
+    mFontOptions = nullptr;
+  }
   MOZ_ASSERT(!mLockedBits);
 }
 
 bool
 DrawTargetCairo::IsValid() const
 {
   return mSurface && !cairo_surface_status(mSurface) &&
          mContext && !cairo_surface_status(cairo_get_group_target(mContext));
@@ -1284,16 +1289,56 @@ DrawTargetCairo::IsCurrentGroupOpaque()
   if (!surf) {
     return false;
   }
 
   return cairo_surface_get_content(surf) == CAIRO_CONTENT_COLOR;
 }
 
 void
+DrawTargetCairo::SetFontOptions()
+{
+  //   This will attempt to detect if the currently set scaled font on the
+  // context has enabled subpixel AA. If it is not permitted, then it will
+  // downgrade to grayscale AA.
+  //   This only currently works effectively for the cairo-ft backend relative
+  // to system defaults, as only cairo-ft reflect system defaults in the scaled
+  // font state. However, this will work for cairo-ft on both tree Cairo and
+  // system Cairo.
+  //   Other backends leave the CAIRO_ANTIALIAS_DEFAULT setting untouched while
+  // potentially interpreting it as subpixel or even other types of AA that
+  // can't be safely equivocated with grayscale AA. For this reason we don't
+  // try to also detect and modify the default AA setting, only explicit
+  // subpixel AA. These other backends must instead rely on tree Cairo's
+  // cairo_surface_set_subpixel_antialiasing extension.
+
+  // If allowing subpixel AA, then leave Cairo's default AA state.
+  if (mPermitSubpixelAA) {
+    return;
+  }
+
+  if (!mFontOptions) {
+    mFontOptions = cairo_font_options_create();
+    if (!mFontOptions) {
+      gfxWarning() << "Failed allocating Cairo font options";
+      return;
+    }
+  }
+
+  // If the current font requests subpixel AA, force it to gray since we don't
+  // allow subpixel AA.
+  cairo_get_font_options(mContext, mFontOptions);
+  cairo_antialias_t antialias = cairo_font_options_get_antialias(mFontOptions);
+  if (antialias == CAIRO_ANTIALIAS_SUBPIXEL) {
+    cairo_font_options_set_antialias(mFontOptions, CAIRO_ANTIALIAS_GRAY);
+    cairo_set_font_options(mContext, mFontOptions);
+  }
+}
+
+void
 DrawTargetCairo::SetPermitSubpixelAA(bool aPermitSubpixelAA)
 {
   DrawTarget::SetPermitSubpixelAA(aPermitSubpixelAA);
 #ifdef MOZ_TREE_CAIRO
   cairo_surface_set_subpixel_antialiasing(cairo_get_group_target(mContext),
     aPermitSubpixelAA ? CAIRO_SUBPIXEL_ANTIALIASING_ENABLED : CAIRO_SUBPIXEL_ANTIALIASING_DISABLED);
 #endif
 }
@@ -1329,16 +1374,19 @@ DrawTargetCairo::FillGlyphs(ScaledFont *
   if (!pat)
     return;
 
   cairo_set_source(mContext, pat);
   cairo_pattern_destroy(pat);
 
   cairo_set_antialias(mContext, GfxAntialiasToCairoAntialias(aOptions.mAntialiasMode));
 
+  // Override any font-specific options as necessary.
+  SetFontOptions();
+
   // Convert our GlyphBuffer into a vector of Cairo glyphs. This code can
   // execute millions of times in short periods, so we want to avoid heap
   // allocation whenever possible. So we use an inline vector capacity of 1024
   // bytes (the maximum allowed by mozilla::Vector), which gives an inline
   // length of 1024 / 24 = 42 elements, which is enough to typically avoid heap
   // allocation in ~99% of cases.
   Vector<cairo_glyph_t, 1024 / sizeof(cairo_glyph_t)> glyphs;
   if (!glyphs.resizeUninitialized(aBuffer.mNumGlyphs)) {
--- a/gfx/2d/DrawTargetCairo.h
+++ b/gfx/2d/DrawTargetCairo.h
@@ -218,24 +218,30 @@ private: // methods
   // Call if there is any reason to disassociate the snapshot from this draw
   // target; for example, because we're going to be destroyed.
   void MarkSnapshotIndependent();
 
   // If the current operator is "source" then clear the destination before we
   // draw into it, to simulate the effect of an unbounded source operator.
   void ClearSurfaceForUnboundedSource(const CompositionOp &aOperator);
 
+  // Set the Cairo context font options according to the current draw target
+  // font state.
+  void SetFontOptions();
+
 private: // data
   cairo_t* mContext;
   cairo_surface_t* mSurface;
   IntSize mSize;
   bool mTransformSingular;
 
   uint8_t* mLockedBits;
 
+  cairo_font_options_t* mFontOptions;
+
   struct PushedLayer
   {
     PushedLayer(Float aOpacity, bool aWasPermittingSubpixelAA)
       : mOpacity(aOpacity)
       , mMaskPattern(nullptr)
       , mWasPermittingSubpixelAA(aWasPermittingSubpixelAA)
     {}
     Float mOpacity;