Clean up usage of mask gamma.
authorbungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 26 Oct 2012 19:35:54 +0000 (19:35 +0000)
committerbungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 26 Oct 2012 19:35:54 +0000 (19:35 +0000)
https://codereview.appspot.com/6749061/

git-svn-id: http://skia.googlecode.com/svn/trunk@6151 2bbb7eff-a529-9590-31e7-b0007b416f81

src/core/SkMaskGamma.h
src/core/SkPaint.cpp
src/core/SkScalerContext.cpp
src/core/SkScalerContext.h
src/ports/SkFontHost_FreeType.cpp
src/ports/SkFontHost_FreeType_common.cpp
src/ports/SkFontHost_FreeType_common.h
src/ports/SkFontHost_mac_coretext.cpp
src/ports/SkFontHost_win.cpp
src/ports/SkFontHost_win_dw.cpp

index a092b20..ba3be64 100644 (file)
@@ -95,8 +95,8 @@ template <int R_LUM_BITS, int G_LUM_BITS, int B_LUM_BITS> class SkTMaskGamma : p
 public:
     SK_DECLARE_INST_COUNT_TEMPLATE(SkTMaskGamma)
 
-    SkTMaskGamma() : fIsLinear(true) {
-    }
+    /** Creates a linear SkTMaskGamma. */
+    SkTMaskGamma() : fIsLinear(true) { }
 
     /**
      * Creates tables to convert linear alpha values to gamma correcting alpha
@@ -110,8 +110,8 @@ public:
     SkTMaskGamma(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma) : fIsLinear(false) {
         const SkColorSpaceLuminance& paintConvert = SkColorSpaceLuminance::Fetch(paintGamma);
         const SkColorSpaceLuminance& deviceConvert = SkColorSpaceLuminance::Fetch(deviceGamma);
-        for (U8CPU i = 0; i < (1 << kLuminanceBits_Max); ++i) {
-            U8CPU lum = sk_t_scale255<kLuminanceBits_Max>(i);
+        for (U8CPU i = 0; i < (1 << MAX_LUM_BITS); ++i) {
+            U8CPU lum = sk_t_scale255<MAX_LUM_BITS>(i);
             SkTMaskGamma_build_correcting_lut(fGammaTables[i], lum, contrast,
                                               paintConvert, paintGamma,
                                               deviceConvert, deviceGamma);
@@ -119,11 +119,11 @@ public:
     }
 
     /** Given a color, returns the closest cannonical color. */
-    static SkColor cannonicalColor(SkColor color) {
+    static SkColor CannonicalColor(SkColor color) {
         return SkColorSetRGB(
-                   sk_t_scale255<kLuminanceBits_R>(SkColorGetR(color) >> (8 - kLuminanceBits_R)),
-                   sk_t_scale255<kLuminanceBits_G>(SkColorGetG(color) >> (8 - kLuminanceBits_G)),
-                   sk_t_scale255<kLuminanceBits_B>(SkColorGetB(color) >> (8 - kLuminanceBits_B)));
+                   sk_t_scale255<R_LUM_BITS>(SkColorGetR(color) >> (8 - R_LUM_BITS)),
+                   sk_t_scale255<G_LUM_BITS>(SkColorGetG(color) >> (8 - G_LUM_BITS)),
+                   sk_t_scale255<B_LUM_BITS>(SkColorGetB(color) >> (8 - B_LUM_BITS)));
     }
 
     /** The type of the mask pre-blend which will be returned from preBlend(SkColor). */
@@ -134,18 +134,13 @@ public:
      * values into gamma correcting alpha values when drawing the given color
      * through the mask. The destination color will be approximated.
      */
-    PreBlend preBlend(SkColor color);
+    PreBlend preBlend(SkColor color) const;
 
 private:
-    enum LuminanceBits {
-        kLuminanceBits_R = R_LUM_BITS,
-        kLuminanceBits_G = G_LUM_BITS,
-        kLuminanceBits_B = B_LUM_BITS,
-        kLuminanceBits_Max = B_LUM_BITS > (R_LUM_BITS > G_LUM_BITS ? R_LUM_BITS : G_LUM_BITS)
-                           ? B_LUM_BITS
-                           : (R_LUM_BITS > G_LUM_BITS ? R_LUM_BITS : G_LUM_BITS)
-    };
-    uint8_t fGammaTables[1 << kLuminanceBits_Max][256];
+    static const int MAX_LUM_BITS =
+          B_LUM_BITS > (R_LUM_BITS > G_LUM_BITS ? R_LUM_BITS : G_LUM_BITS)
+        ? B_LUM_BITS : (R_LUM_BITS > G_LUM_BITS ? R_LUM_BITS : G_LUM_BITS);
+    uint8_t fGammaTables[1 << MAX_LUM_BITS][256];
     bool fIsLinear;
 
     typedef SkRefCnt INHERITED;
@@ -163,29 +158,35 @@ SK_DEFINE_INST_COUNT_TEMPLATE(
  * value for that channel. This class is immutable.
  *
  * If fR, fG, or fB is NULL, all of them will be. This indicates that no mask
- * pre blend should be applied.
+ * pre blend should be applied. SkTMaskPreBlend::isApplicable() is provided as
+ * a convenience function to test for the absence of this case.
  */
 template <int R_LUM_BITS, int G_LUM_BITS, int B_LUM_BITS> class SkTMaskPreBlend {
 private:
-    SkTMaskPreBlend(SkTMaskGamma<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>* parent,
-                    const uint8_t* r,
-                    const uint8_t* g,
-                    const uint8_t* b)
-    : fParent(parent), fR(r), fG(g), fB(b) {
-        SkSafeRef(parent);
-    }
-    SkAutoTUnref<SkTMaskGamma<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS> > fParent;
+    SkTMaskPreBlend(const SkTMaskGamma<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>* parent,
+                    const uint8_t* r, const uint8_t* g, const uint8_t* b)
+    : fParent(SkSafeRef(parent)), fR(r), fG(g), fB(b) { }
+
+    SkAutoTUnref<const SkTMaskGamma<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS> > fParent;
     friend class SkTMaskGamma<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>;
 public:
+    /** Creates a non applicable SkTMaskPreBlend. */
+    SkTMaskPreBlend() : fParent(), fR(NULL), fG(NULL), fB(NULL) { }
+
     /**
      * This copy contructor exists for correctness, but should never be called
      * when return value optimization is enabled.
      */
     SkTMaskPreBlend(const SkTMaskPreBlend<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>& that)
-    : fParent(that.fParent.get()), fR(that.fR), fG(that.fG), fB(that.fB) {
-        SkSafeRef(fParent.get());
-    }
+    : fParent(SkSafeRef(that.fParent.get())), fR(that.fR), fG(that.fG), fB(that.fB) { }
+
     ~SkTMaskPreBlend() { }
+
+    /** True if this PreBlend should be applied. When false, fR, fG, and fB are NULL. */
+    bool isApplicable() const {
+        return NULL != this->fG;
+    }
+
     const uint8_t* fR;
     const uint8_t* fG;
     const uint8_t* fB;
@@ -193,14 +194,12 @@ public:
 
 template <int R_LUM_BITS, int G_LUM_BITS, int B_LUM_BITS>
 SkTMaskPreBlend<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>
-SkTMaskGamma<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>::preBlend(SkColor color) {
-    return fIsLinear ? SkTMaskPreBlend<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>(
-                          NULL, NULL, NULL, NULL)
-                      : SkTMaskPreBlend<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>(
-                          this,
-                          fGammaTables[SkColorGetR(color) >> (8 - kLuminanceBits_Max)],
-                          fGammaTables[SkColorGetG(color) >> (8 - kLuminanceBits_Max)],
-                          fGammaTables[SkColorGetB(color) >> (8 - kLuminanceBits_Max)]);
+SkTMaskGamma<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>::preBlend(SkColor color) const {
+    return fIsLinear ? SkTMaskPreBlend<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>()
+                     : SkTMaskPreBlend<R_LUM_BITS, G_LUM_BITS, B_LUM_BITS>(this,
+                         fGammaTables[SkColorGetR(color) >> (8 - MAX_LUM_BITS)],
+                         fGammaTables[SkColorGetG(color) >> (8 - MAX_LUM_BITS)],
+                         fGammaTables[SkColorGetB(color) >> (8 - MAX_LUM_BITS)]);
 }
 
 ///@{
index c517663..41c2f75 100644 (file)
@@ -1647,12 +1647,12 @@ static SkScalar gDeviceGamma = SK_ScalarMin;
  * The caller must hold the gMaskGammaCacheMutex and continue to hold it until
  * the returned SkMaskGamma pointer is refed or forgotten.
  */
-static SkMaskGamma* cachedMaskGamma(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma) {
+static const SkMaskGamma& cachedMaskGamma(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma) {
     if (0 == contrast && SK_Scalar1 == paintGamma && SK_Scalar1 == deviceGamma) {
         if (NULL == gLinearMaskGamma) {
             gLinearMaskGamma = SkNEW(SkMaskGamma);
         }
-        return gLinearMaskGamma;
+        return *gLinearMaskGamma;
     }
     if (gContrast != contrast || gPaintGamma != paintGamma || gDeviceGamma != deviceGamma) {
         SkSafeUnref(gMaskGamma);
@@ -1661,7 +1661,7 @@ static SkMaskGamma* cachedMaskGamma(SkScalar contrast, SkScalar paintGamma, SkSc
         gPaintGamma = paintGamma;
         gDeviceGamma = deviceGamma;
     }
-    return gMaskGamma;
+    return *gMaskGamma;
 }
 
 /*static*/ void SkPaint::Term() {
@@ -1690,7 +1690,7 @@ void SkScalerContext::PostMakeRec(const SkPaint& paint, SkScalerContext::Rec* re
         case SkMask::kLCD32_Format: {
             // filter down the luminance color to a finite number of bits
             SkColor color = rec->getLuminanceColor();
-            rec->setLuminanceColor(SkMaskGamma::cannonicalColor(color));
+            rec->setLuminanceColor(SkMaskGamma::CannonicalColor(color));
             break;
         }
         case SkMask::kA8_Format: {
@@ -1707,7 +1707,7 @@ void SkScalerContext::PostMakeRec(const SkPaint& paint, SkScalerContext::Rec* re
 
             // reduce to our finite number of bits
             color = SkColorSetRGB(lum, lum, lum);
-            rec->setLuminanceColor(SkMaskGamma::cannonicalColor(color));
+            rec->setLuminanceColor(SkMaskGamma::CannonicalColor(color));
             break;
         }
         case SkMask::kBW_Format:
@@ -1762,6 +1762,11 @@ void SkPaint::descriptorProc(const SkMatrix* deviceMatrix,
         descSize += mfBuffer.size();
         entryCount += 1;
         rec.fMaskFormat = SkMask::kA8_Format;   // force antialiasing with maskfilters
+        /* Pre-blend is not currently applied to filtered text.
+           The primary filter is blur, for which contrast makes no sense,
+           and for which the destination guess error is more visible.
+           Also, all existing users of blur have calibrated for linear. */
+        rec.ignorePreBlend();
     }
     if (ra) {
         raBuffer.writeFlattenable(ra);
@@ -1853,10 +1858,10 @@ SkGlyphCache* SkPaint::detachCache(const SkMatrix* deviceMatrix) const {
 //static
 SkMaskGamma::PreBlend SkScalerContext::GetMaskPreBlend(const SkScalerContext::Rec& rec) {
     SkAutoMutexAcquire ama(gMaskGammaCacheMutex);
-    SkMaskGamma* maskGamma = cachedMaskGamma(rec.getContrast(),
-                                             rec.getPaintGamma(),
-                                             rec.getDeviceGamma());
-    return maskGamma->preBlend(rec.getLuminanceColor());
+    const SkMaskGamma& maskGamma = cachedMaskGamma(rec.getContrast(),
+                                                   rec.getPaintGamma(),
+                                                   rec.getDeviceGamma());
+    return maskGamma.preBlend(rec.getLuminanceColor());
 }
 
 ///////////////////////////////////////////////////////////////////////////////
index 0a46d20..a497c3b 100644 (file)
@@ -77,14 +77,21 @@ static SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag) {
 
 SkScalerContext::SkScalerContext(const SkDescriptor* desc)
     : fRec(*static_cast<const Rec*>(desc->findEntry(kRec_SkDescriptorTag, NULL)))
+
     , fBaseGlyphCount(0)
+
     , fPathEffect(static_cast<SkPathEffect*>(load_flattenable(desc, kPathEffect_SkDescriptorTag)))
     , fMaskFilter(static_cast<SkMaskFilter*>(load_flattenable(desc, kMaskFilter_SkDescriptorTag)))
     , fRasterizer(static_cast<SkRasterizer*>(load_flattenable(desc, kRasterizer_SkDescriptorTag)))
-      // initialize based on our settings. subclasses can also force this
+
+      // Initialize based on our settings. Subclasses can also force this.
     , fGenerateImageFromPath(fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL)
+
     , fNextContext(NULL)
-    , fMaskPreBlend(SkScalerContext::GetMaskPreBlend(fRec))
+
+    , fPreBlend(fMaskFilter ? SkMaskGamma::PreBlend() : SkScalerContext::GetMaskPreBlend(fRec))
+    , fPreBlendForFilter(fMaskFilter ? SkScalerContext::GetMaskPreBlend(fRec)
+                                     : SkMaskGamma::PreBlend())
 {
 #ifdef DUMP_REC
     desc->assertChecksum();
@@ -339,8 +346,22 @@ SK_ERROR:
     glyph->fMaskFormat = fRec.fMaskFormat;
 }
 
+
+static void applyLUTToA8Mask(const SkMask& mask, const uint8_t* lut) {
+    uint8_t* SK_RESTRICT dst = (uint8_t*)mask.fImage;
+    unsigned rowBytes = mask.fRowBytes;
+
+    for (int y = mask.fBounds.height() - 1; y >= 0; --y) {
+        for (int x = mask.fBounds.width() - 1; x >= 0; --x) {
+            dst[x] = lut[dst[x]];
+        }
+        dst += rowBytes;
+    }
+}
+
 template<bool APPLY_PREBLEND>
-static void pack3xHToLCD16(const SkBitmap& src, const SkMask& dst, SkMaskGamma::PreBlend* maskPreBlend) {
+static void pack3xHToLCD16(const SkBitmap& src, const SkMask& dst,
+                           const SkMaskGamma::PreBlend& maskPreBlend) {
     SkASSERT(SkBitmap::kA8_Config == src.config());
     SkASSERT(SkMask::kLCD16_Format == dst.fFormat);
 
@@ -349,21 +370,12 @@ static void pack3xHToLCD16(const SkBitmap& src, const SkMask& dst, SkMaskGamma::
     uint16_t* dstP = (uint16_t*)dst.fImage;
     size_t dstRB = dst.fRowBytes;
 
-    const uint8_t* maskPreBlendR = NULL;
-    const uint8_t* maskPreBlendG = NULL;
-    const uint8_t* maskPreBlendB = NULL;
-    if (APPLY_PREBLEND) {
-        maskPreBlendR = maskPreBlend->fR;
-        maskPreBlendG = maskPreBlend->fG;
-        maskPreBlendB = maskPreBlend->fB;
-    }
-
     for (int y = 0; y < height; ++y) {
         const uint8_t* srcP = src.getAddr8(0, y);
         for (int x = 0; x < width; ++x) {
-            U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlendR);
-            U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlendG);
-            U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlendB);
+            U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fR);
+            U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fG);
+            U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fB);
             dstP[x] = SkPack888ToRGB16(r, g, b);
         }
         dstP = (uint16_t*)((char*)dstP + dstRB);
@@ -371,7 +383,8 @@ static void pack3xHToLCD16(const SkBitmap& src, const SkMask& dst, SkMaskGamma::
 }
 
 template<bool APPLY_PREBLEND>
-static void pack3xHToLCD32(const SkBitmap& src, const SkMask& dst, SkMaskGamma::PreBlend* maskPreBlend) {
+static void pack3xHToLCD32(const SkBitmap& src, const SkMask& dst,
+                           const SkMaskGamma::PreBlend& maskPreBlend) {
     SkASSERT(SkBitmap::kA8_Config == src.config());
     SkASSERT(SkMask::kLCD32_Format == dst.fFormat);
 
@@ -380,28 +393,20 @@ static void pack3xHToLCD32(const SkBitmap& src, const SkMask& dst, SkMaskGamma::
     SkPMColor* dstP = (SkPMColor*)dst.fImage;
     size_t dstRB = dst.fRowBytes;
 
-    const uint8_t* maskPreBlendR = NULL;
-    const uint8_t* maskPreBlendG = NULL;
-    const uint8_t* maskPreBlendB = NULL;
-    if (APPLY_PREBLEND) {
-        maskPreBlendR = maskPreBlend->fR;
-        maskPreBlendG = maskPreBlend->fG;
-        maskPreBlendB = maskPreBlend->fB;
-    }
-
     for (int y = 0; y < height; ++y) {
         const uint8_t* srcP = src.getAddr8(0, y);
         for (int x = 0; x < width; ++x) {
-            U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlendR);
-            U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlendG);
-            U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlendB);
+            U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fR);
+            U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fG);
+            U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fB);
             dstP[x] = SkPackARGB32(0xFF, r, g, b);
         }
         dstP = (SkPMColor*)((char*)dstP + dstRB);
     }
 }
 
-static void generateMask(const SkMask& mask, const SkPath& path, SkMaskGamma::PreBlend* maskPreBlend) {
+static void generateMask(const SkMask& mask, const SkPath& path,
+                         const SkMaskGamma::PreBlend& maskPreBlend) {
     SkBitmap::Config config;
     SkPaint     paint;
 
@@ -459,15 +464,19 @@ static void generateMask(const SkMask& mask, const SkPath& path, SkMaskGamma::Pr
 
     if (0 == dstRB) {
         switch (mask.fFormat) {
+            case SkMask::kA8_Format:
+                if (maskPreBlend.isApplicable()) {
+                    applyLUTToA8Mask(mask, maskPreBlend.fG);
+                }
             case SkMask::kLCD16_Format:
-                if (maskPreBlend) {
+                if (maskPreBlend.isApplicable()) {
                     pack3xHToLCD16<true>(bm, mask, maskPreBlend);
                 } else {
                     pack3xHToLCD16<false>(bm, mask, maskPreBlend);
                 }
                 break;
             case SkMask::kLCD32_Format:
-                if (maskPreBlend) {
+                if (maskPreBlend.isApplicable()) {
                     pack3xHToLCD32<true>(bm, mask, maskPreBlend);
                 } else {
                     pack3xHToLCD32<false>(bm, mask, maskPreBlend);
@@ -479,22 +488,9 @@ static void generateMask(const SkMask& mask, const SkPath& path, SkMaskGamma::Pr
     }
 }
 
-static void applyLUTToA8Glyph(const SkGlyph& glyph, const uint8_t* lut) {
-      uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
-      unsigned rowBytes = glyph.rowBytes();
-
-      for (int y = glyph.fHeight - 1; y >= 0; --y) {
-          for (int x = glyph.fWidth - 1; x >= 0; --x) {
-              dst[x] = lut[dst[x]];
-          }
-          dst += rowBytes;
-      }
-}
-
 void SkScalerContext::getImage(const SkGlyph& origGlyph) {
     const SkGlyph*  glyph = &origGlyph;
     SkGlyph         tmpGlyph;
-    SkMaskGamma::PreBlend* maskPreBlend = fMaskPreBlend.fG ? &fMaskPreBlend : NULL;
 
     if (fMaskFilter) {   // restore the prefilter bounds
         tmpGlyph.init(origGlyph.fID);
@@ -511,7 +507,6 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) {
         SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth);
         SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight);
         glyph = &tmpGlyph;
-        maskPreBlend = NULL;
     }
 
     if (fGenerateImageFromPath) {
@@ -531,19 +526,14 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) {
                                         SkMask::kJustRenderImage_CreateMode)) {
                 return;
             }
-            //apply maskPreBlend to a8 (if not NULL)
-            if (maskPreBlend) {
-              applyLUTToA8Glyph(*glyph, maskPreBlend->fG);
+            if (fPreBlend.isApplicable()) {
+                applyLUTToA8Mask(mask, fPreBlend.fG);
             }
         } else {
-            generateMask(mask, devPath, maskPreBlend);
-            //apply maskPreBlend to a8 (if not NULL) -- already applied to lcd.
-            if (maskPreBlend && mask.fFormat == SkMask::kA8_Format) {
-                applyLUTToA8Glyph(*glyph, maskPreBlend->fG);
-            }
+            generateMask(mask, devPath, fPreBlend);
         }
     } else {
-        this->getGlyphContext(*glyph)->generateImage(*glyph, maskPreBlend);
+        this->getGlyphContext(*glyph)->generateImage(*glyph);
     }
 
     if (fMaskFilter) {
@@ -579,10 +569,9 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) {
             }
             SkMask::FreeImage(dstM.fImage);
 
-            /* Pre-blend is not currently applied to filtered text.
-               The primary filter is blur, for which contrast makes no sense,
-               and for which the destination guess error is more visible. */
-            //applyLUTToA8Glyph(origGlyph, fMaskPreBlend.fG);
+            if (fPreBlendForFilter.isApplicable()) {
+                applyLUTToA8Mask(srcM, fPreBlendForFilter.fG);
+            }
         }
     }
 }
@@ -739,22 +728,22 @@ public:
     SkScalerContext_Empty(const SkDescriptor* desc) : SkScalerContext(desc) {}
 
 protected:
-    virtual unsigned generateGlyphCount() {
+    virtual unsigned generateGlyphCount() SK_OVERRIDE {
         return 0;
     }
-    virtual uint16_t generateCharToGlyph(SkUnichar uni) {
+    virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE {
         return 0;
     }
-    virtual void generateAdvance(SkGlyph* glyph) {
+    virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE {
         glyph->zeroMetrics();
     }
-    virtual void generateMetrics(SkGlyph* glyph) {
+    virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE {
         glyph->zeroMetrics();
     }
-    virtual void generateImage(const SkGlyph& glyph, SkMaskGamma::PreBlend* maskPreBlend) {}
-    virtual void generatePath(const SkGlyph& glyph, SkPath* path) {}
+    virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE {}
+    virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE {}
     virtual void generateFontMetrics(SkPaint::FontMetrics* mx,
-                                     SkPaint::FontMetrics* my) {
+                                     SkPaint::FontMetrics* my) SK_OVERRIDE {
         if (mx) {
             sk_bzero(mx, sizeof(*mx));
         }
index 8175582..b637e84 100644 (file)
@@ -216,7 +216,7 @@ protected:
     virtual uint16_t generateCharToGlyph(SkUnichar) = 0;
     virtual void generateAdvance(SkGlyph*) = 0;
     virtual void generateMetrics(SkGlyph*) = 0;
-    virtual void generateImage(const SkGlyph&, SkMaskGamma::PreBlend* maskPreBlend) = 0;
+    virtual void generateImage(const SkGlyph&) = 0;
     virtual void generatePath(const SkGlyph&, SkPath*) = 0;
     virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
                                      SkPaint::FontMetrics* mY) = 0;
@@ -247,8 +247,14 @@ private:
     // link-list of context, to handle missing chars. null-terminated.
     SkScalerContext* fNextContext;
 
-    // converts linear masks to gamma correcting masks.
-    SkMaskGamma::PreBlend fMaskPreBlend;
+    // SkMaskGamma::PreBlend converts linear masks to gamma correcting masks.
+protected:
+    // Visible to subclasses so that generateImage can apply the pre-blend directly.
+    const SkMaskGamma::PreBlend fPreBlend;
+private:
+    // When there is a filter, previous steps must create a linear mask
+    // and the pre-blend applied as a final step.
+    const SkMaskGamma::PreBlend fPreBlendForFilter;
 };
 
 #define kRec_SkDescriptorTag            SkSetFourByteTag('s', 'r', 'e', 'c')
index c3f7595..35dc22b 100644 (file)
@@ -169,15 +169,15 @@ public:
     }
 
 protected:
-    virtual unsigned generateGlyphCount();
-    virtual uint16_t generateCharToGlyph(SkUnichar uni);
-    virtual void generateAdvance(SkGlyph* glyph);
-    virtual void generateMetrics(SkGlyph* glyph);
-    virtual void generateImage(const SkGlyph& glyph, SkMaskGamma::PreBlend* maskPreBlend);
-    virtual void generatePath(const SkGlyph& glyph, SkPath* path);
+    virtual unsigned generateGlyphCount() SK_OVERRIDE;
+    virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
+    virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
+    virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
+    virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
+    virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
     virtual void generateFontMetrics(SkPaint::FontMetrics* mx,
-                                     SkPaint::FontMetrics* my);
-    virtual SkUnichar generateGlyphToChar(uint16_t glyph);
+                                     SkPaint::FontMetrics* my) SK_OVERRIDE;
+    virtual SkUnichar generateGlyphToChar(uint16_t glyph) SK_OVERRIDE;
 
 private:
     SkFaceRec*  fFaceRec;
@@ -1135,7 +1135,7 @@ void SkScalerContext_FreeType::generateMetrics(SkGlyph* glyph) {
 }
 
 
-void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph, SkMaskGamma::PreBlend* maskPreBlend) {
+void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) {
     SkAutoMutexAcquire  ac(gFTMutex);
 
     FT_Error    err;
@@ -1153,7 +1153,7 @@ void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph, SkMaskGamma::
         return;
     }
 
-    generateGlyphImage(fFace, glyph, maskPreBlend);
+    generateGlyphImage(fFace, glyph);
 }
 
 
index 3a827d7..a6fb0dc 100644 (file)
@@ -119,20 +119,7 @@ static void copyFT2LCD16(const SkGlyph& glyph, const FT_Bitmap& bitmap,
     }
 }
 
-void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face,
-                                                       const SkGlyph& glyph,
-                                                       SkMaskGamma::PreBlend* maskPreBlend)
-{
-    //Must be careful not to use these if maskPreBlend == NULL
-    const uint8_t* tableR = NULL;
-    const uint8_t* tableG = NULL;
-    const uint8_t* tableB = NULL;
-    if (maskPreBlend) {
-        tableR = maskPreBlend->fR;
-        tableG = maskPreBlend->fG;
-        tableB = maskPreBlend->fB;
-    }
-
+void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face, const SkGlyph& glyph) {
     const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag);
     const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag);
 
@@ -167,12 +154,12 @@ void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face,
 
             if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
                 FT_Render_Glyph(face->glyph, doVert ? FT_RENDER_MODE_LCD_V : FT_RENDER_MODE_LCD);
-                if (maskPreBlend) {
+                if (fPreBlend.isApplicable()) {
                     copyFT2LCD16<true>(glyph, face->glyph->bitmap, doBGR, doVert,
-                                       tableR, tableG, tableB);
+                                       fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
                 } else {
                     copyFT2LCD16<false>(glyph, face->glyph->bitmap, doBGR, doVert,
-                                        tableR, tableG, tableB);
+                                        fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
                 }
             } else {
                 target.width = glyph.fWidth;
@@ -238,12 +225,12 @@ void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face,
                     dst += glyph.rowBytes();
                 }
             } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
-                if (maskPreBlend) {
+                if (fPreBlend.isApplicable()) {
                     copyFT2LCD16<true>(glyph, face->glyph->bitmap, doBGR, doVert,
-                                       tableR, tableG, tableB);
+                                       fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
                 } else {
                     copyFT2LCD16<false>(glyph, face->glyph->bitmap, doBGR, doVert,
-                                        tableR, tableG, tableB);
+                                        fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
                 }
             } else {
                 SkDEBUGFAIL("unknown glyph bitmap transform needed");
@@ -259,13 +246,13 @@ void SkScalerContext_FreeType_Base::generateGlyphImage(FT_Face face,
 // We used to always do this pre-USE_COLOR_LUMINANCE, but with colorlum,
 // it is optional
 #if defined(SK_GAMMA_APPLY_TO_A8)
-    if (SkMask::kA8_Format == glyph.fMaskFormat && maskPreBlend) {
+    if (SkMask::kA8_Format == glyph.fMaskFormat && fPreBlend.isApplicable()) {
         uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage;
         unsigned rowBytes = glyph.rowBytes();
 
         for (int y = glyph.fHeight - 1; y >= 0; --y) {
             for (int x = glyph.fWidth - 1; x >= 0; --x) {
-                dst[x] = tableG[dst[x]];
+                dst[x] = fPreBlend.fG[dst[x]];
             }
             dst += rowBytes;
         }
index d5f2c08..01100de 100644 (file)
@@ -36,7 +36,7 @@ public:
     {}
 
 protected:
-    void generateGlyphImage(FT_Face face, const SkGlyph& glyph, SkMaskGamma::PreBlend* maskPreBlend);
+    void generateGlyphImage(FT_Face face, const SkGlyph& glyph);
     void generateGlyphPath(FT_Face face, const SkGlyph& glyph, SkPath* path);
     void emboldenOutline(FT_Face face, FT_Outline* outline);
 };
index e385337..27e0437 100644 (file)
@@ -617,7 +617,7 @@ protected:
     uint16_t                            generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
     void                                generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
     void                                generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
-    void                                generateImage(const SkGlyph& glyph, SkMaskGamma::PreBlend* maskPreBlend) SK_OVERRIDE;
+    void                                generateImage(const SkGlyph& glyph) SK_OVERRIDE;
     void                                generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
     void                                generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY) SK_OVERRIDE;
 
@@ -1198,7 +1198,7 @@ template <typename T> T* SkTAddByteOffset(T* ptr, size_t byteOffset) {
     return (T*)((char*)ptr + byteOffset);
 }
 
-void SkScalerContext_Mac::generateImage(const SkGlyph& glyph, SkMaskGamma::PreBlend* maskPreBlend) {
+void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) {
     CGGlyph cgGlyph = (CGGlyph) glyph.getGlyphID(fBaseGlyphCount);
 
     // FIXME: lcd smoothed un-hinted rasterization unsupported.
@@ -1237,37 +1237,31 @@ void SkScalerContext_Mac::generateImage(const SkGlyph& glyph, SkMaskGamma::PreBl
         }
     }
 
-    // Must be careful not to use these if maskPreBlend == NULL
-    const uint8_t* tableR = NULL;
-    const uint8_t* tableG = NULL;
-    const uint8_t* tableB = NULL;
-    if (maskPreBlend) {
-        tableR = maskPreBlend->fR;
-        tableG = maskPreBlend->fG;
-        tableB = maskPreBlend->fB;
-    }
-
     // Convert glyph to mask
     switch (glyph.fMaskFormat) {
         case SkMask::kLCD32_Format: {
-            if (maskPreBlend) {
-                rgb_to_lcd32<true>(cgPixels, cgRowBytes, glyph, tableR, tableG, tableB);
+            if (fPreBlend.isApplicable()) {
+                rgb_to_lcd32<true>(cgPixels, cgRowBytes, glyph,
+                                   fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
             } else {
-                rgb_to_lcd32<false>(cgPixels, cgRowBytes, glyph, tableR, tableG, tableB);
+                rgb_to_lcd32<false>(cgPixels, cgRowBytes, glyph,
+                                    fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
             }
         } break;
         case SkMask::kLCD16_Format: {
-            if (maskPreBlend) {
-                rgb_to_lcd16<true>(cgPixels, cgRowBytes, glyph, tableR, tableG, tableB);
+            if (fPreBlend.isApplicable()) {
+                rgb_to_lcd16<true>(cgPixels, cgRowBytes, glyph,
+                                   fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
             } else {
-                rgb_to_lcd16<false>(cgPixels, cgRowBytes, glyph, tableR, tableG, tableB);
+                rgb_to_lcd16<false>(cgPixels, cgRowBytes, glyph,
+                                    fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
             }
         } break;
         case SkMask::kA8_Format: {
-            if (maskPreBlend) {
-                rgb_to_a8<true>(cgPixels, cgRowBytes, glyph, tableG);
+            if (fPreBlend.isApplicable()) {
+                rgb_to_a8<true>(cgPixels, cgRowBytes, glyph, fPreBlend.fG);
             } else {
-                rgb_to_a8<false>(cgPixels, cgRowBytes, glyph, tableG);
+                rgb_to_a8<false>(cgPixels, cgRowBytes, glyph, fPreBlend.fG);
             }
         } break;
         case SkMask::kBW_Format: {
index f2603e9..9a377c0 100755 (executable)
@@ -548,9 +548,10 @@ protected:
     virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
     virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
     virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
-    virtual void generateImage(const SkGlyph& glyph, SkMaskGamma::PreBlend* maskPreBlend) SK_OVERRIDE;
+    virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
     virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
-    virtual void generateFontMetrics(SkPaint::FontMetrics* mX, SkPaint::FontMetrics* mY) SK_OVERRIDE;
+    virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
+                                     SkPaint::FontMetrics* mY) SK_OVERRIDE;
 
 private:
     HDCOffscreen fOffscreen;
@@ -1134,20 +1135,10 @@ static inline unsigned clamp255(unsigned x) {
     return x - (x >> 8);
 }
 
-void SkScalerContext_Windows::generateImage(const SkGlyph& glyph, SkMaskGamma::PreBlend* maskPreBlend) {
+void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) {
     SkAutoMutexAcquire ac(gFTMutex);
     SkASSERT(fDDC);
 
-    //Must be careful not to use these if maskPreBlend == NULL
-    const uint8_t* tableR = NULL;
-    const uint8_t* tableG = NULL;
-    const uint8_t* tableB = NULL;
-    if (maskPreBlend) {
-        tableR = maskPreBlend->fR;
-        tableG = maskPreBlend->fG;
-        tableB = maskPreBlend->fB;
-    }
-
     const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
     const bool isAA = !isLCD(fRec);
 
@@ -1202,10 +1193,10 @@ void SkScalerContext_Windows::generateImage(const SkGlyph& glyph, SkMaskGamma::P
         // since the caller may require A8 for maskfilters, we can't check for BW
         // ... until we have the caller tell us that explicitly
         const SkGdiRGB* src = (const SkGdiRGB*)bits;
-        if (maskPreBlend) {
-            rgb_to_a8<true>(src, srcRB, glyph, tableG);
+        if (fPreBlend.isApplicable()) {
+            rgb_to_a8<true>(src, srcRB, glyph, fPreBlend.fG);
         } else {
-            rgb_to_a8<false>(src, srcRB, glyph, tableG);
+            rgb_to_a8<false>(src, srcRB, glyph, fPreBlend.fG);
         }
     } else {    // LCD16
         const SkGdiRGB* src = (const SkGdiRGB*)bits;
@@ -1214,17 +1205,21 @@ void SkScalerContext_Windows::generateImage(const SkGlyph& glyph, SkMaskGamma::P
             ((SkGlyph*)&glyph)->fMaskFormat = SkMask::kBW_Format;
         } else {
             if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
-                if (maskPreBlend) {
-                    rgb_to_lcd16<true>(src, srcRB, glyph, tableR, tableG, tableB);
+                if (fPreBlend.isApplicable()) {
+                    rgb_to_lcd16<true>(src, srcRB, glyph,
+                                       fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
                 } else {
-                    rgb_to_lcd16<false>(src, srcRB, glyph, tableR, tableG, tableB);
+                    rgb_to_lcd16<false>(src, srcRB, glyph,
+                                        fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
                 }
             } else {
                 SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
-                if (maskPreBlend) {
-                    rgb_to_lcd32<true>(src, srcRB, glyph, tableR, tableG, tableB);
+                if (fPreBlend.isApplicable()) {
+                    rgb_to_lcd32<true>(src, srcRB, glyph,
+                                       fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
                 } else {
-                    rgb_to_lcd32<false>(src, srcRB, glyph, tableR, tableG, tableB);
+                    rgb_to_lcd32<false>(src, srcRB, glyph,
+                                        fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
                 }
             }
         }
index 82d44ee..67ee5c4 100644 (file)
@@ -489,8 +489,7 @@ protected:
     virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE;
     virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE;
     virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE;
-    virtual void generateImage(const SkGlyph& glyph,
-                               SkMaskGamma::PreBlend* maskPreBlend) SK_OVERRIDE;
+    virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE;
     virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE;
     virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
                                      SkPaint::FontMetrics* mY) SK_OVERRIDE;
@@ -975,20 +974,9 @@ static void rgb_to_lcd32(const uint8_t* SK_RESTRICT src, const SkGlyph& glyph,
     }
 }
 
-void SkScalerContext_Windows::generateImage(const SkGlyph& glyph,
-                                            SkMaskGamma::PreBlend* maskPreBlend) {
+void SkScalerContext_Windows::generateImage(const SkGlyph& glyph) {
     SkAutoMutexAcquire ac(gFTMutex);
 
-    //Must be careful not to use these if maskPreBlend == NULL
-    const uint8_t* tableR = NULL;
-    const uint8_t* tableG = NULL;
-    const uint8_t* tableB = NULL;
-    if (maskPreBlend) {
-        tableR = maskPreBlend->fR;
-        tableG = maskPreBlend->fG;
-        tableB = maskPreBlend->fB;
-    }
-
     const bool isBW = SkMask::kBW_Format == fRec.fMaskFormat;
     const bool isAA = !isLCD(fRec);
 
@@ -1006,23 +994,23 @@ void SkScalerContext_Windows::generateImage(const SkGlyph& glyph,
     if (isBW) {
         bilevel_to_bw(src, glyph);
     } else if (isAA) {
-        if (maskPreBlend) {
-            rgb_to_a8<true>(src, glyph, tableG);
+        if (fPreBlend.isApplicable()) {
+            rgb_to_a8<true>(src, glyph, fPreBlend.fG);
         } else {
-            rgb_to_a8<false>(src, glyph, tableG);
+            rgb_to_a8<false>(src, glyph, fPreBlend.fG);
         }
     } else if (SkMask::kLCD16_Format == glyph.fMaskFormat) {
-        if (maskPreBlend) {
-            rgb_to_lcd16<true>(src, glyph, tableR, tableG, tableB);
+        if (fPreBlend.isApplicable()) {
+            rgb_to_lcd16<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
         } else {
-            rgb_to_lcd16<false>(src, glyph, tableR, tableG, tableB);
+            rgb_to_lcd16<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
         }
     } else {
         SkASSERT(SkMask::kLCD32_Format == glyph.fMaskFormat);
-        if (maskPreBlend) {
-            rgb_to_lcd32<true>(src, glyph, tableR, tableG, tableB);
+        if (fPreBlend.isApplicable()) {
+            rgb_to_lcd32<true>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
         } else {
-            rgb_to_lcd32<false>(src, glyph, tableR, tableG, tableB);
+            rgb_to_lcd32<false>(src, glyph, fPreBlend.fR, fPreBlend.fG, fPreBlend.fB);
         }
     }
 }