diff options
author | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-05-02 18:55:44 +0000 |
---|---|---|
committer | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-05-02 18:55:44 +0000 |
commit | 5bdfb331ac650cf464baa96a49e2473ee10a515c (patch) | |
tree | ffd328cfee5da4bc5fb29be5af06ed97e69086d0 | |
parent | ce3d223cfe1b9dbb694dba6b8826b1fb187e667f (diff) |
Detect color masks, and divert to draw-sprite instead of maskblitters.
Review URL: https://codereview.chromium.org/14637007
git-svn-id: http://skia.googlecode.com/svn/trunk@8967 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | include/core/SkMask.h | 15 | ||||
-rw-r--r-- | src/core/SkDraw.cpp | 24 | ||||
-rw-r--r-- | src/core/SkDrawProcs.h | 19 | ||||
-rw-r--r-- | src/core/SkScalerContext.cpp | 60 |
4 files changed, 108 insertions, 10 deletions
diff --git a/include/core/SkMask.h b/include/core/SkMask.h index 4265595f26..4cf3ae7307 100644 --- a/include/core/SkMask.h +++ b/include/core/SkMask.h @@ -98,7 +98,20 @@ struct SkMask { uint32_t* row = (uint32_t*)(fImage + (y - fBounds.fTop) * fRowBytes); return row + (x - fBounds.fLeft); } - + + /** + * Return the address of the specified 32bit mask. In the debug build, + * this asserts that the mask's format is 32bits, and that (x,y) + * are contained in the mask's fBounds. + */ + uint32_t* getAddr32(int x, int y) const { + SkASSERT(kLCD32_Format == fFormat || kARGB32_Format == fFormat); + SkASSERT(fBounds.contains(x, y)); + SkASSERT(fImage != NULL); + uint32_t* row = (uint32_t*)(fImage + (y - fBounds.fTop) * fRowBytes); + return row + (x - fBounds.fLeft); + } + /** * Returns the address of the specified pixel, computing the pixel-size * at runtime based on the mask format. This will be slightly slower than diff --git a/src/core/SkDraw.cpp b/src/core/SkDraw.cpp index 3c3e3a34fd..fc615ab0ef 100644 --- a/src/core/SkDraw.cpp +++ b/src/core/SkDraw.cpp @@ -1489,7 +1489,7 @@ static void D1G_NoBounder_RectClip(const SkDraw1Glyph& state, mask.fRowBytes = glyph.rowBytes(); mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); mask.fImage = aa; - state.fBlitter->blitMask(mask, *bounds); + state.blitMask(mask, *bounds); } static void D1G_NoBounder_RgnClip(const SkDraw1Glyph& state, @@ -1523,7 +1523,7 @@ static void D1G_NoBounder_RgnClip(const SkDraw1Glyph& state, mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); mask.fImage = (uint8_t*)aa; do { - state.fBlitter->blitMask(mask, cr); + state.blitMask(mask, cr); clipper.next(); } while (!clipper.done()); } @@ -1563,7 +1563,7 @@ static void D1G_Bounder(const SkDraw1Glyph& state, mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat); mask.fImage = (uint8_t*)aa; do { - state.fBlitter->blitMask(mask, cr); + state.blitMask(mask, cr); clipper.next(); } while (!clipper.done()); } @@ -1592,11 +1592,12 @@ static bool needsRasterTextBlit(const SkDraw& draw) { } SkDraw1Glyph::Proc SkDraw1Glyph::init(const SkDraw* draw, SkBlitter* blitter, - SkGlyphCache* cache) { + SkGlyphCache* cache, const SkPaint& pnt) { fDraw = draw; fBounder = draw->fBounder; fBlitter = blitter; fCache = cache; + fPaint = &pnt; if (cache->isSubpixel()) { fHalfSampleX = fHalfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits); @@ -1636,6 +1637,17 @@ SkDraw1Glyph::Proc SkDraw1Glyph::init(const SkDraw* draw, SkBlitter* blitter, } } +void SkDraw1Glyph::blitMaskAsSprite(const SkMask& mask) const { + SkASSERT(SkMask::kARGB32_Format == mask.fFormat); + + SkBitmap bm; + bm.setConfig(SkBitmap::kARGB_8888_Config, + mask.fBounds.width(), mask.fBounds.height(), mask.fRowBytes); + bm.setPixels((SkPMColor*)mask.fImage); + + fDraw->drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), *fPaint); +} + /////////////////////////////////////////////////////////////////////////////// void SkDraw::drawText(const char text[], size_t byteLength, @@ -1704,7 +1716,7 @@ void SkDraw::drawText(const char text[], size_t byteLength, SkAutoKern autokern; SkDraw1Glyph d1g; - SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache); + SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint); SkFixed fxMask = ~0; SkFixed fyMask = ~0; @@ -1866,7 +1878,7 @@ void SkDraw::drawPosText(const char text[], size_t byteLength, const char* stop = text + byteLength; AlignProc alignProc = pick_align_proc(paint.getTextAlign()); SkDraw1Glyph d1g; - SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache); + SkDraw1Glyph::Proc proc = d1g.init(this, blitter, cache, paint); TextMapState tms(*fMatrix, constY); TextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition); diff --git a/src/core/SkDrawProcs.h b/src/core/SkDrawProcs.h index 68cc9ff08c..8b8c382667 100644 --- a/src/core/SkDrawProcs.h +++ b/src/core/SkDrawProcs.h @@ -8,6 +8,7 @@ #ifndef SkDrawProcs_DEFINED #define SkDrawProcs_DEFINED +#include "SkBlitter.h" #include "SkDraw.h" class SkAAClip; @@ -20,6 +21,7 @@ struct SkDraw1Glyph { const SkAAClip* fAAClip; SkBlitter* fBlitter; SkGlyphCache* fCache; + const SkPaint* fPaint; SkIRect fClipBounds; /** Half the sampling frequency of the rasterized glyph in x. */ SkFixed fHalfSampleX; @@ -35,7 +37,22 @@ struct SkDraw1Glyph { */ typedef void (*Proc)(const SkDraw1Glyph&, SkFixed x, SkFixed y, const SkGlyph&); - Proc init(const SkDraw* draw, SkBlitter* blitter, SkGlyphCache* cache); + 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) { + this->blitMaskAsSprite(mask); + } else { + fBlitter->blitMask(mask, clip); + } + } + + // mask must be kARGB32_Format + void blitMaskAsSprite(const SkMask& mask) const; }; struct SkDrawProcs { diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp index c02dbca93b..fa4f863cee 100644 --- a/src/core/SkScalerContext.cpp +++ b/src/core/SkScalerContext.cpp @@ -337,6 +337,12 @@ void SkScalerContext::getMetrics(SkGlyph* glyph) { glyph->fMaskFormat = fRec.fMaskFormat; } + // If we are going to create the mask, then we cannot keep the color + if ((fGenerateImageFromPath || fMaskFilter) && + SkMask::kARGB32_Format == glyph->fMaskFormat) { + glyph->fMaskFormat = SkMask::kA8_Format; + } + if (fMaskFilter) { SkMask src, dst; SkMatrix matrix; @@ -515,10 +521,40 @@ static void generateMask(const SkMask& mask, const SkPath& path, } } +static void extract_alpha(const SkMask& dst, + const SkPMColor* srcRow, size_t srcRB) { + int width = dst.fBounds.width(); + int height = dst.fBounds.height(); + int dstRB = dst.fRowBytes; + uint8_t* dstRow = dst.fImage; + + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + dstRow[x] = SkGetPackedA32(srcRow[x]); + } + // zero any padding on each row + for (int x = width; x < dstRB; ++x) { + dstRow[x] = 0; + } + dstRow += dstRB; + srcRow = (const SkPMColor*)((const char*)srcRow + srcRB); + } +} + void SkScalerContext::getImage(const SkGlyph& origGlyph) { const SkGlyph* glyph = &origGlyph; SkGlyph tmpGlyph; + // in case we need to call generateImage on a mask-format that is different + // (i.e. larger) than what our caller allocated by looking at origGlyph. + SkAutoMalloc tmpGlyphImageStorage; + + // If we are going to draw-from-path, then we cannot generate color, since + // the path only makes a mask. This case should have been caught up in + // generateMetrics(). + SkASSERT(!fGenerateImageFromPath || + SkMask::kARGB32_Format != origGlyph.fMaskFormat); + if (fMaskFilter) { // restore the prefilter bounds tmpGlyph.init(origGlyph.fID); @@ -528,11 +564,16 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) { this->getMetrics(&tmpGlyph); fMaskFilter = mf; // restore - tmpGlyph.fImage = origGlyph.fImage; - // we need the prefilter bounds to be <= filter bounds SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth); SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight); + + if (tmpGlyph.fMaskFormat == origGlyph.fMaskFormat) { + tmpGlyph.fImage = origGlyph.fImage; + } else { + tmpGlyphImageStorage.reset(tmpGlyph.computeImageSize()); + tmpGlyph.fImage = tmpGlyphImageStorage.get(); + } glyph = &tmpGlyph; } @@ -557,6 +598,7 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) { applyLUTToA8Mask(mask, fPreBlend.fG); } } else { + SkASSERT(SkMask::kARGB32_Format != mask.fFormat); generateMask(mask, devPath, fPreBlend); } } else { @@ -569,7 +611,21 @@ void SkScalerContext::getImage(const SkGlyph& origGlyph) { // the src glyph image shouldn't be 3D SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat); + + SkAutoSMalloc<32*32> a8storage; glyph->toMask(&srcM); + if (SkMask::kARGB32_Format == srcM.fFormat) { + // now we need to extract the alpha-channel from the glyph's image + // and copy it into a temp buffer, and then point srcM at that temp. + srcM.fFormat = SkMask::kA8_Format; + srcM.fRowBytes = SkAlign4(srcM.fBounds.width()); + size_t size = srcM.computeImageSize(); + a8storage.reset(size); + srcM.fImage = (uint8_t*)a8storage.get(); + extract_alpha(srcM, + (const SkPMColor*)glyph->fImage, glyph->rowBytes()); + } + fRec.getMatrixFrom2x2(&matrix); if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) { |