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
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);
}
/** 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). */
* 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;
* 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;
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)]);
}
///@{
* 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);
gPaintGamma = paintGamma;
gDeviceGamma = deviceGamma;
}
- return gMaskGamma;
+ return *gMaskGamma;
}
/*static*/ void SkPaint::Term() {
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: {
// 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:
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);
//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());
}
///////////////////////////////////////////////////////////////////////////////
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();
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);
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);
}
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);
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;
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);
}
}
-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);
SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth);
SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight);
glyph = &tmpGlyph;
- maskPreBlend = NULL;
}
if (fGenerateImageFromPath) {
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) {
}
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);
+ }
}
}
}
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));
}
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;
// 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')
}
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;
}
-void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph, SkMaskGamma::PreBlend* maskPreBlend) {
+void SkScalerContext_FreeType::generateImage(const SkGlyph& glyph) {
SkAutoMutexAcquire ac(gFTMutex);
FT_Error err;
return;
}
- generateGlyphImage(fFace, glyph, maskPreBlend);
+ generateGlyphImage(fFace, glyph);
}
}
}
-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);
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;
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");
// 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;
}
{}
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);
};
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;
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.
}
}
- // 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: {
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;
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);
// 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;
((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);
}
}
}
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;
}
}
-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);
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);
}
}
}