Index: src/core/SkDraw.cpp |
diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp |
index 2fa6273112cf0975623755f6a4b04b4a8c386b45..e1a49d39b4a582265dda15c430ffbf95578bc297 100644 |
--- a/src/core/SkDraw.cpp |
+++ b/src/core/SkDraw.cpp |
@@ -1423,120 +1423,170 @@ |
#endif |
//////////////////////////////////////////////////////////////////////////////////////////////////// |
- |
-class DrawOneGlyph { |
-public: |
- DrawOneGlyph(const SkDraw& draw, const SkPaint& paint, SkGlyphCache* cache, SkBlitter* blitter) |
- : fUseRegionToDraw(UsingRegionToDraw(draw.fRC)) |
- , fGlyphCache(cache) |
- , fBlitter(blitter) |
- , fClip(fUseRegionToDraw ? &draw.fRC->bwRgn() : nullptr) |
- , fDraw(draw) |
- , fPaint(paint) |
- , fClipBounds(PickClipBounds(draw)) { } |
- |
- void operator()(const SkGlyph& glyph, SkPoint position, SkPoint rounding) { |
- position += rounding; |
- Sk48Dot16 fx = SkScalarTo48Dot16(position.fX); |
- Sk48Dot16 fy = SkScalarTo48Dot16(position.fY); |
- // Prevent glyphs from being drawn outside of or straddling the edge of device space. |
- if ((fx >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) || |
- (fx >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/) || |
- (fy >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) || |
- (fy >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) { |
- return; |
- } |
- |
- int left = Sk48Dot16FloorToInt(fx); |
- int top = Sk48Dot16FloorToInt(fy); |
- SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); |
- |
- left += glyph.fLeft; |
- top += glyph.fTop; |
- |
- int right = left + glyph.fWidth; |
- int bottom = top + glyph.fHeight; |
- |
- SkMask mask; |
- mask.fBounds.set(left, top, right, bottom); |
- |
- if (fUseRegionToDraw) { |
- SkRegion::Cliperator clipper(*fClip, mask.fBounds); |
- |
- if (!clipper.done() && this->getImageData(glyph, &mask)) { |
- const SkIRect& cr = clipper.rect(); |
- do { |
- this->blitMask(mask, cr); |
- clipper.next(); |
- } while (!clipper.done()); |
- } |
- } else { |
- SkIRect storage; |
- SkIRect* bounds = &mask.fBounds; |
- |
- // this extra test is worth it, assuming that most of the time it succeeds |
- // since we can avoid writing to storage |
- if (!fClipBounds.containsNoEmptyCheck(mask.fBounds)) { |
- if (!storage.intersectNoEmptyCheck(mask.fBounds, fClipBounds)) |
- return; |
- bounds = &storage; |
- } |
- |
- if (this->getImageData(glyph, &mask)) { |
- this->blitMask(mask, *bounds); |
- } |
- } |
- } |
- |
-private: |
- static bool UsingRegionToDraw(const SkRasterClip* rClip) { |
- return rClip->isBW() && !rClip->isRect(); |
- } |
- |
- static SkIRect PickClipBounds(const SkDraw& draw) { |
- const SkRasterClip& rasterClip = *draw.fRC; |
- |
- if (rasterClip.isBW()) { |
- return rasterClip.bwRgn().getBounds(); |
- } else { |
- return rasterClip.aaRgn().getBounds(); |
- } |
- } |
- |
- bool getImageData(const SkGlyph& glyph, SkMask* mask) { |
- uint8_t* bits = (uint8_t*)(fGlyphCache->findImage(glyph)); |
- if (nullptr == bits) { |
- return false; // can't rasterize glyph |
- } |
- mask->fImage = bits; |
- mask->fRowBytes = glyph.rowBytes(); |
- mask->fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); |
- return true; |
- } |
- |
+struct SkDraw1Glyph { |
+ const SkDraw* fDraw; |
+ const SkRegion* fClip; |
+ const SkAAClip* fAAClip; |
+ SkBlitter* fBlitter; |
+ SkGlyphCache* fCache; |
+ const SkPaint* fPaint; |
+ SkIRect fClipBounds; |
+ /** Half the sampling frequency of the rasterized glyph in x. */ |
+ SkScalar fHalfSampleX; |
+ /** Half the sampling frequency of the rasterized glyph in y. */ |
+ SkScalar fHalfSampleY; |
+ |
+ /** Draws one glyph. |
+ * |
+ * The x and y are pre-biased, so implementations may just truncate them. |
+ * i.e. half the sampling frequency has been added. |
+ * e.g. 1/2 or 1/(2^(SkGlyph::kSubBits+1)) has already been added. |
+ * This added bias can be found in fHalfSampleX,Y. |
+ */ |
+ typedef void (*Proc)(const SkDraw1Glyph&, Sk48Dot16 x, Sk48Dot16 y, const SkGlyph&); |
+ |
+ Proc init(const SkDraw* draw, SkBlitter* blitter, SkGlyphCache* cache, |
+ const SkPaint&); |
+ |
+ // call this instead of fBlitter->blitMask() since this wrapper will handle |
+ // the case when the mask is ARGB32_Format |
+ // |
void blitMask(const SkMask& mask, const SkIRect& clip) const { |
if (SkMask::kARGB32_Format == mask.fFormat) { |
- SkBitmap bm; |
- bm.installPixels( |
- SkImageInfo::MakeN32Premul(mask.fBounds.width(), mask.fBounds.height()), |
- (SkPMColor*)mask.fImage, mask.fRowBytes); |
- |
- fDraw.drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), fPaint); |
+ this->blitMaskAsSprite(mask); |
} else { |
fBlitter->blitMask(mask, clip); |
} |
} |
- const bool fUseRegionToDraw; |
- SkGlyphCache * const fGlyphCache; |
- SkBlitter * const fBlitter; |
- const SkRegion* const fClip; |
- const SkDraw& fDraw; |
- const SkPaint& fPaint; |
- const SkIRect fClipBounds; |
+ // mask must be kARGB32_Format |
+ void blitMaskAsSprite(const SkMask& mask) const; |
}; |
-//////////////////////////////////////////////////////////////////////////////////////////////////// |
+static void D1G_RectClip(const SkDraw1Glyph& state, Sk48Dot16 fx, Sk48Dot16 fy, |
+ const SkGlyph& glyph) { |
+ // Prevent glyphs from being drawn outside of or straddling the edge of device space. |
+ if ((fx >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) || |
+ (fx >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/) || |
+ (fy >> 16) > INT_MAX - (INT16_MAX + UINT16_MAX) || |
+ (fy >> 16) < INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) |
+ { |
+ return; |
+ } |
+ |
+ int left = Sk48Dot16FloorToInt(fx); |
+ int top = Sk48Dot16FloorToInt(fy); |
+ SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); |
+ SkASSERT((nullptr == state.fClip && state.fAAClip) || |
+ (state.fClip && nullptr == state.fAAClip && state.fClip->isRect())); |
+ |
+ left += glyph.fLeft; |
+ top += glyph.fTop; |
+ |
+ int right = left + glyph.fWidth; |
+ int bottom = top + glyph.fHeight; |
+ |
+ SkMask mask; |
+ SkIRect storage; |
+ SkIRect* bounds = &mask.fBounds; |
+ |
+ mask.fBounds.set(left, top, right, bottom); |
+ |
+ // this extra test is worth it, assuming that most of the time it succeeds |
+ // since we can avoid writing to storage |
+ if (!state.fClipBounds.containsNoEmptyCheck(left, top, right, bottom)) { |
+ if (!storage.intersectNoEmptyCheck(mask.fBounds, state.fClipBounds)) |
+ return; |
+ bounds = &storage; |
+ } |
+ |
+ uint8_t* aa = (uint8_t*)glyph.fImage; |
+ if (nullptr == aa) { |
+ aa = (uint8_t*)state.fCache->findImage(glyph); |
+ if (nullptr == aa) { |
+ return; // can't rasterize glyph |
+ } |
+ } |
+ |
+ mask.fRowBytes = glyph.rowBytes(); |
+ mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); |
+ mask.fImage = aa; |
+ state.blitMask(mask, *bounds); |
+} |
+ |
+static void D1G_RgnClip(const SkDraw1Glyph& state, Sk48Dot16 fx, Sk48Dot16 fy, |
+ const SkGlyph& glyph) { |
+ int left = Sk48Dot16FloorToInt(fx); |
+ int top = Sk48Dot16FloorToInt(fy); |
+ SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); |
+ SkASSERT(!state.fClip->isRect()); |
+ |
+ SkMask mask; |
+ |
+ left += glyph.fLeft; |
+ top += glyph.fTop; |
+ |
+ mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight); |
+ SkRegion::Cliperator clipper(*state.fClip, mask.fBounds); |
+ |
+ if (!clipper.done()) { |
+ const SkIRect& cr = clipper.rect(); |
+ const uint8_t* aa = (uint8_t*)state.fCache->findImage(glyph); |
+ if (nullptr == aa) { |
+ return; |
+ } |
+ |
+ mask.fRowBytes = glyph.rowBytes(); |
+ mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); |
+ mask.fImage = (uint8_t*)aa; |
+ do { |
+ state.blitMask(mask, cr); |
+ clipper.next(); |
+ } while (!clipper.done()); |
+ } |
+} |
+ |
+SkDraw1Glyph::Proc SkDraw1Glyph::init(const SkDraw* draw, SkBlitter* blitter, SkGlyphCache* cache, |
+ const SkPaint& pnt) { |
+ fDraw = draw; |
+ fBlitter = blitter; |
+ fCache = cache; |
+ fPaint = &pnt; |
+ |
+ if (cache->isSubpixel()) { |
+ fHalfSampleX = fHalfSampleY = SkFixedToScalar(SkGlyph::kSubpixelRound); |
+ } else { |
+ fHalfSampleX = fHalfSampleY = SK_ScalarHalf; |
+ } |
+ |
+ if (draw->fRC->isBW()) { |
+ fAAClip = nullptr; |
+ fClip = &draw->fRC->bwRgn(); |
+ fClipBounds = fClip->getBounds(); |
+ if (fClip->isRect()) { |
+ return D1G_RectClip; |
+ } else { |
+ return D1G_RgnClip; |
+ } |
+ } else { // aaclip |
+ fAAClip = &draw->fRC->aaRgn(); |
+ fClip = nullptr; |
+ fClipBounds = fAAClip->getBounds(); |
+ return D1G_RectClip; |
+ } |
+} |
+ |
+void SkDraw1Glyph::blitMaskAsSprite(const SkMask& mask) const { |
+ SkASSERT(SkMask::kARGB32_Format == mask.fFormat); |
+ |
+ SkBitmap bm; |
+ bm.installPixels(SkImageInfo::MakeN32Premul(mask.fBounds.width(), mask.fBounds.height()), |
+ (SkPMColor*)mask.fImage, mask.fRowBytes); |
+ |
+ fDraw->drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), *fPaint); |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
void SkDraw::drawText(const char text[], size_t byteLength, |
SkScalar x, SkScalar y, const SkPaint& paint) const { |
@@ -1556,17 +1606,25 @@ |
return; |
} |
- SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix); |
- SkGlyphCache* cache = autoCache.getCache(); |
+ SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix); |
+ SkGlyphCache* cache = autoCache.getCache(); |
+ |
// The Blitter Choose needs to be live while using the blitter below. |
SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); |
SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); |
- DrawOneGlyph drawOneGlyph(*this, paint, cache, wrapper.getBlitter()); |
+ |
+ SkDraw1Glyph d1g; |
+ SkDraw1Glyph::Proc proc = d1g.init(this, wrapper.getBlitter(), cache, paint); |
SkFindAndPlaceGlyph::ProcessText( |
paint.getTextEncoding(), text, byteLength, |
- {x, y}, *fMatrix, paint.getTextAlign(), cache, drawOneGlyph); |
+ {x, y}, *fMatrix, paint.getTextAlign(), cache, |
+ [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { |
+ position += rounding; |
+ proc(d1g, SkScalarTo48Dot16(position.fX), SkScalarTo48Dot16(position.fY), glyph); |
+ } |
+ ); |
} |
////////////////////////////////////////////////////////////////////////////// |
@@ -1638,18 +1696,24 @@ |
return; |
} |
- SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix); |
- SkGlyphCache* cache = autoCache.getCache(); |
- |
// The Blitter Choose needs to be live while using the blitter below. |
SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint); |
SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get()); |
- DrawOneGlyph drawOneGlyph(*this, paint, cache, wrapper.getBlitter()); |
- SkPaint::Align textAlignment = paint.getTextAlign(); |
+ |
+ SkAutoGlyphCache autoCache(paint, &fDevice->surfaceProps(), fMatrix); |
+ SkGlyphCache* cache = autoCache.getCache(); |
+ SkDraw1Glyph d1g; |
+ SkDraw1Glyph::Proc proc = d1g.init(this, wrapper.getBlitter(), cache, paint); |
+ SkPaint::Align textAlignment = paint.getTextAlign(); |
SkFindAndPlaceGlyph::ProcessPosText( |
paint.getTextEncoding(), text, byteLength, |
- offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache, drawOneGlyph); |
+ offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache, |
+ [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { |
+ position += rounding; |
+ proc(d1g, SkScalarTo48Dot16(position.fX), SkScalarTo48Dot16(position.fY), glyph); |
+ } |
+ ); |
} |
#if defined _WIN32 && _MSC_VER >= 1300 |