aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-05-02 18:55:44 +0000
committerGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-05-02 18:55:44 +0000
commit5bdfb331ac650cf464baa96a49e2473ee10a515c (patch)
treeffd328cfee5da4bc5fb29be5af06ed97e69086d0
parentce3d223cfe1b9dbb694dba6b8826b1fb187e667f (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.h15
-rw-r--r--src/core/SkDraw.cpp24
-rw-r--r--src/core/SkDrawProcs.h19
-rw-r--r--src/core/SkScalerContext.cpp60
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)) {