diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp index e1a49d39b4..2fa6273112 100644 --- a/src/core/SkDraw.cpp +++ b/src/core/SkDraw.cpp @@ -1423,170 +1423,120 @@ void SkDraw::drawText_asPaths(const char text[], size_t byteLength, #endif //////////////////////////////////////////////////////////////////////////////////////////////////// -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&); +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)) { } - Proc init(const SkDraw* draw, SkBlitter* blitter, SkGlyphCache* cache, - const SkPaint&); + 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(glyph.fMaskFormat); + return true; + } - // 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) { - this->blitMaskAsSprite(mask); + 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); } else { fBlitter->blitMask(mask, clip); } } - // mask must be kARGB32_Format - void blitMaskAsSprite(const SkMask& mask) const; + const bool fUseRegionToDraw; + SkGlyphCache * const fGlyphCache; + SkBlitter * const fBlitter; + const SkRegion* const fClip; + const SkDraw& fDraw; + const SkPaint& fPaint; + const SkIRect fClipBounds; }; -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(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(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 { @@ -1606,25 +1556,17 @@ void SkDraw::drawText(const char text[], size_t byteLength, 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()); - - SkDraw1Glyph d1g; - SkDraw1Glyph::Proc proc = d1g.init(this, wrapper.getBlitter(), cache, paint); + DrawOneGlyph drawOneGlyph(*this, paint, cache, wrapper.getBlitter()); SkFindAndPlaceGlyph::ProcessText( paint.getTextEncoding(), text, byteLength, - {x, y}, *fMatrix, paint.getTextAlign(), cache, - [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { - position += rounding; - proc(d1g, SkScalarTo48Dot16(position.fX), SkScalarTo48Dot16(position.fY), glyph); - } - ); + {x, y}, *fMatrix, paint.getTextAlign(), cache, drawOneGlyph); } ////////////////////////////////////////////////////////////////////////////// @@ -1696,24 +1638,18 @@ void SkDraw::drawPosText(const char text[], size_t byteLength, 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()); - - 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(); + DrawOneGlyph drawOneGlyph(*this, paint, cache, wrapper.getBlitter()); + SkPaint::Align textAlignment = paint.getTextAlign(); SkFindAndPlaceGlyph::ProcessPosText( paint.getTextEncoding(), text, byteLength, - offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache, - [&](const SkGlyph& glyph, SkPoint position, SkPoint rounding) { - position += rounding; - proc(d1g, SkScalarTo48Dot16(position.fX), SkScalarTo48Dot16(position.fY), glyph); - } - ); + offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache, drawOneGlyph); } #if defined _WIN32 && _MSC_VER >= 1300