merge in ics-mr1-release history after reset to ics-mr1
diff --git a/include/core/SkDrawLooper.h b/include/core/SkDrawLooper.h
index 270abc2..3830b4a 100644
--- a/include/core/SkDrawLooper.h
+++ b/include/core/SkDrawLooper.h
@@ -52,6 +52,20 @@
*/
virtual bool next(SkCanvas*, SkPaint* paint) = 0;
+ /**
+ * The fast bounds functions are used to enable the paint to be culled early
+ * in the drawing pipeline. If a subclass can support this feature it must
+ * return true for the canComputeFastBounds() function. If that function
+ * returns false then computeFastBounds behavior is undefined otherwise it
+ * is expected to have the following behavior. Given the parent paint and
+ * the parent's bounding rect the subclass must fill in and return the
+ * storage rect, where the storage rect is with the union of the src rect
+ * and the looper's bounding rect.
+ */
+ virtual bool canComputeFastBounds(const SkPaint& paint);
+ virtual void computeFastBounds(const SkPaint& paint,
+ const SkRect& src, SkRect* dst);
+
protected:
SkDrawLooper() {}
SkDrawLooper(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {}
diff --git a/include/core/SkMaskFilter.h b/include/core/SkMaskFilter.h
index 641ad83..60dade9 100644
--- a/include/core/SkMaskFilter.h
+++ b/include/core/SkMaskFilter.h
@@ -72,6 +72,19 @@
virtual void flatten(SkFlattenableWriteBuffer& ) {}
+ /**
+ * The fast bounds function is used to enable the paint to be culled early
+ * in the drawing pipeline. This function accepts the current bounds of the
+ * paint as its src param and the filter adjust those bounds using its
+ * current mask and returns the result using the dest param. Callers are
+ * allowed to provide the same struct for both src and dest so each
+ * implementation must accomodate that behavior.
+ *
+ * The default impl calls filterMask with the src mask having no image,
+ * but subclasses may override this if they can compute the rect faster.
+ */
+ virtual void computeFastBounds(const SkRect& src, SkRect* dest);
+
protected:
// empty for now, but lets get our subclass to remember to init us for the future
SkMaskFilter(SkFlattenableReadBuffer&) {}
diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h
index f336f5b..9b547a4 100644
--- a/include/core/SkPaint.h
+++ b/include/core/SkPaint.h
@@ -18,7 +18,7 @@
#define SkPaint_DEFINED
#include "SkColor.h"
-#include "SkMath.h"
+#include "SkDrawLooper.h"
#include "SkXfermode.h"
class SkAutoGlyphCache;
@@ -35,7 +35,6 @@
class SkPathEffect;
class SkRasterizer;
class SkShader;
-class SkDrawLooper;
class SkTypeface;
typedef const SkGlyph& (*SkDrawCacheProc)(SkGlyphCache*, const char**,
@@ -425,10 +424,11 @@
the bounds computation expensive.
*/
bool canComputeFastBounds() const {
+ if (this->getLooper()) {
+ return this->getLooper()->canComputeFastBounds(*this);
+ }
// use bit-or since no need for early exit
- return (reinterpret_cast<uintptr_t>(this->getMaskFilter()) |
- reinterpret_cast<uintptr_t>(this->getLooper()) |
- reinterpret_cast<uintptr_t>(this->getRasterizer()) |
+ return (reinterpret_cast<uintptr_t>(this->getRasterizer()) |
reinterpret_cast<uintptr_t>(this->getPathEffect())) == 0;
}
@@ -454,8 +454,12 @@
}
*/
const SkRect& computeFastBounds(const SkRect& orig, SkRect* storage) const {
- return this->getStyle() == kFill_Style ? orig :
- this->computeStrokeFastBounds(orig, storage);
+ if (this->getStyle() == kFill_Style &&
+ !this->getLooper() && !this->getMaskFilter()) {
+ return orig;
+ }
+
+ return this->doComputeFastBounds(orig, storage);
}
/** Get the paint's shader object.
@@ -864,8 +868,7 @@
void (*proc)(const SkDescriptor*, void*),
void* context, bool ignoreGamma = false) const;
- const SkRect& computeStrokeFastBounds(const SkRect& orig,
- SkRect* storage) const;
+ const SkRect& doComputeFastBounds(const SkRect& orig, SkRect* storage) const;
enum {
kCanonicalTextSizeForPaths = 64
diff --git a/src/core/SkMaskFilter.cpp b/src/core/SkMaskFilter.cpp
index a278261..2008c93 100644
--- a/src/core/SkMaskFilter.cpp
+++ b/src/core/SkMaskFilter.cpp
@@ -57,4 +57,19 @@
return true;
}
+void SkMaskFilter::computeFastBounds(const SkRect& src, SkRect* dst) {
+ SkMask srcM, dstM;
+
+ srcM.fImage = NULL;
+ src.roundOut(&srcM.fBounds);
+ srcM.fRowBytes = 0;
+ srcM.fFormat = SkMask::kA8_Format;
+
+ SkIPoint margin; // ignored
+ if (this->filterMask(&dstM, srcM, SkMatrix::I(), &margin)) {
+ dst->set(dstM.fBounds);
+ } else {
+ dst->set(srcM.fBounds);
+ }
+}
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index c29c4f0..21bd078 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -17,7 +17,6 @@
#include "SkPaint.h"
#include "SkColorFilter.h"
-#include "SkDrawLooper.h"
#include "SkFontHost.h"
#include "SkMaskFilter.h"
#include "SkPathEffect.h"
@@ -1703,23 +1702,38 @@
return width != 0; // return true if we're filled, or false if we're hairline (width == 0)
}
-const SkRect& SkPaint::computeStrokeFastBounds(const SkRect& src,
- SkRect* storage) const {
+const SkRect& SkPaint::doComputeFastBounds(const SkRect& src,
+ SkRect* storage) const {
SkASSERT(storage);
- SkASSERT(this->getStyle() != SkPaint::kFill_Style);
- // since we're stroked, outset the rect by the radius (and join type)
- SkScalar radius = SkScalarHalf(this->getStrokeWidth());
- if (0 == radius) { // hairline
- radius = SK_Scalar1;
- } else if (this->getStrokeJoin() == SkPaint::kMiter_Join) {
- SkScalar scale = this->getStrokeMiter();
- if (scale > SK_Scalar1) {
- radius = SkScalarMul(radius, scale);
- }
+ if (this->getLooper()) {
+ SkASSERT(this->getLooper()->canComputeFastBounds(*this));
+ this->getLooper()->computeFastBounds(*this, src, storage);
+ return *storage;
}
- storage->set(src.fLeft - radius, src.fTop - radius,
- src.fRight + radius, src.fBottom + radius);
+
+ if (this->getStyle() != SkPaint::kFill_Style) {
+ // since we're stroked, outset the rect by the radius (and join type)
+ SkScalar radius = SkScalarHalf(this->getStrokeWidth());
+ if (0 == radius) { // hairline
+ radius = SK_Scalar1;
+ } else if (this->getStrokeJoin() == SkPaint::kMiter_Join) {
+ SkScalar scale = this->getStrokeMiter();
+ if (scale > SK_Scalar1) {
+ radius = SkScalarMul(radius, scale);
+ }
+ }
+ storage->set(src.fLeft - radius, src.fTop - radius,
+ src.fRight + radius, src.fBottom + radius);
+ } else {
+ *storage = src;
+ }
+
+ // check the mask filter
+ if (this->getMaskFilter()) {
+ this->getMaskFilter()->computeFastBounds(*storage, storage);
+ }
+
return *storage;
}
@@ -1811,3 +1825,48 @@
}
return NULL;
}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool SkDrawLooper::canComputeFastBounds(const SkPaint& paint) {
+ SkCanvas canvas;
+
+ this->init(&canvas);
+ for (;;) {
+ SkPaint p(paint);
+ if (this->next(&canvas, &p)) {
+ p.setLooper(NULL);
+ if (!p.canComputeFastBounds()) {
+ return false;
+ }
+ } else {
+ break;
+ }
+ }
+ return true;
+}
+
+void SkDrawLooper::computeFastBounds(const SkPaint& paint, const SkRect& src,
+ SkRect* dst) {
+ SkCanvas canvas;
+
+ this->init(&canvas);
+ for (bool firstTime = true;; firstTime = false) {
+ SkPaint p(paint);
+ if (this->next(&canvas, &p)) {
+ SkRect r(src);
+
+ p.setLooper(NULL);
+ p.computeFastBounds(r, &r);
+ canvas.getTotalMatrix().mapRect(&r);
+
+ if (firstTime) {
+ *dst = r;
+ } else {
+ dst->join(r);
+ }
+ } else {
+ break;
+ }
+ }
+}
diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h
index 697b399..4db61f7 100644
--- a/src/core/SkPictureFlat.h
+++ b/src/core/SkPictureFlat.h
@@ -25,6 +25,7 @@
DRAW_PICTURE,
DRAW_POINTS,
DRAW_POS_TEXT,
+ DRAW_POS_TEXT_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT
DRAW_POS_TEXT_H,
DRAW_POS_TEXT_H_TOP_BOTTOM, // fast variant of DRAW_POS_TEXT_H
DRAW_RECT,
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index 80189ab..5a856ef 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -625,6 +625,17 @@
const SkPoint* pos = (const SkPoint*)fReader.skip(points * sizeof(SkPoint));
canvas.drawPosText(text.text(), text.length(), pos, paint);
} break;
+ case DRAW_POS_TEXT_TOP_BOTTOM: {
+ const SkPaint& paint = *getPaint();
+ getText(&text);
+ size_t points = getInt();
+ const SkPoint* pos = (const SkPoint*)fReader.skip(points * sizeof(SkPoint));
+ const SkScalar top = fReader.readScalar();
+ const SkScalar bottom = fReader.readScalar();
+ if (!canvas.quickRejectY(top, bottom, SkCanvas::kAA_EdgeType)) {
+ canvas.drawPosText(text.text(), text.length(), pos, paint);
+ }
+ } break;
case DRAW_POS_TEXT_H: {
const SkPaint& paint = *getPaint();
getText(&text);
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index 6b2b330..5810051 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -242,14 +242,14 @@
}
void SkPictureRecord::addFontMetricsTopBottom(const SkPaint& paint,
- SkScalar baselineY) {
+ SkScalar minY, SkScalar maxY) {
SkPaint::FontMetrics metrics;
paint.getFontMetrics(&metrics);
SkRect bounds;
// construct a rect so we can see any adjustments from the paint.
// we use 0,1 for left,right, just so the rect isn't empty
- bounds.set(0, metrics.fTop + baselineY,
- SK_Scalar1, metrics.fBottom + baselineY);
+ bounds.set(0, metrics.fTop + minY,
+ SK_Scalar1, metrics.fBottom + maxY);
(void)paint.computeFastBounds(bounds, &bounds);
// now record the top and bottom
addScalar(bounds.fTop);
@@ -266,7 +266,7 @@
addScalar(x);
addScalar(y);
if (fast) {
- addFontMetricsTopBottom(paint, y);
+ addFontMetricsTopBottom(paint, y, y);
}
validate();
}
@@ -278,23 +278,34 @@
return;
bool canUseDrawH = true;
+ SkScalar minY = pos[0].fY;
+ SkScalar maxY = pos[0].fY;
// check if the caller really should have used drawPosTextH()
{
const SkScalar firstY = pos[0].fY;
for (size_t index = 1; index < points; index++) {
if (pos[index].fY != firstY) {
canUseDrawH = false;
- break;
+ if (pos[index].fY < minY) {
+ minY = pos[index].fY;
+ } else if (pos[index].fY > maxY) {
+ maxY = pos[index].fY;
+ }
}
}
}
- bool fast = canUseDrawH && paint.canComputeFastBounds();
+ bool fastBounds = paint.canComputeFastBounds();
+ bool fast = canUseDrawH && fastBounds;
if (fast) {
addDraw(DRAW_POS_TEXT_H_TOP_BOTTOM);
+ } else if (canUseDrawH) {
+ addDraw(DRAW_POS_TEXT_H);
+ } else if (fastBounds) {
+ addDraw(DRAW_POS_TEXT_TOP_BOTTOM);
} else {
- addDraw(canUseDrawH ? DRAW_POS_TEXT_H : DRAW_POS_TEXT);
+ addDraw(DRAW_POS_TEXT);
}
addPaint(paint);
addText(text, byteLength);
@@ -305,7 +316,7 @@
#endif
if (canUseDrawH) {
if (fast) {
- addFontMetricsTopBottom(paint, pos[0].fY);
+ addFontMetricsTopBottom(paint, pos[0].fY, pos[0].fY);
}
addScalar(pos[0].fY);
SkScalar* xptr = (SkScalar*)fWriter.reserve(points * sizeof(SkScalar));
@@ -314,6 +325,9 @@
}
else {
fWriter.writeMul4(pos, points * sizeof(SkPoint));
+ if (fastBounds) {
+ addFontMetricsTopBottom(paint, minY, maxY);
+ }
}
#ifdef SK_DEBUG_SIZE
fPointBytes += fWriter.size() - start;
@@ -340,7 +354,7 @@
size_t start = fWriter.size();
#endif
if (fast) {
- addFontMetricsTopBottom(paint, constY);
+ addFontMetricsTopBottom(paint, constY, constY);
}
addScalar(constY);
fWriter.writeMul4(xpos, points * sizeof(SkScalar));
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index e0d6a50..5a400cb 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -59,8 +59,8 @@
const SkPaint&);
virtual void drawData(const void*, size_t);
- void addFontMetricsTopBottom(const SkPaint& paint, SkScalar baselineY);
-
+ void addFontMetricsTopBottom(const SkPaint& paint, SkScalar minY, SkScalar maxY);
+
const SkTDArray<const SkFlatBitmap* >& getBitmaps() const {
return fBitmaps;
}
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index 41e04b8..ad00d17 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -27,6 +27,7 @@
// overrides from SkMaskFilter
virtual SkMask::Format getFormat();
virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix& matrix, SkIPoint* margin);
+ virtual void computeFastBounds(const SkRect& src, SkRect* dst);
// overrides from SkFlattenable
// This method is not exported to java.
@@ -111,6 +112,11 @@
return false;
}
+void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src, SkRect* dst) {
+ dst->set(src.fLeft - fRadius, src.fTop - fRadius,
+ src.fRight + fRadius, src.fBottom + fRadius);
+}
+
SkFlattenable* SkBlurMaskFilterImpl::CreateProc(SkFlattenableReadBuffer& buffer)
{
return SkNEW_ARGS(SkBlurMaskFilterImpl, (buffer));
diff --git a/src/effects/SkLayerDrawLooper.cpp b/src/effects/SkLayerDrawLooper.cpp
index 5d0fdcf..74cc624 100644
--- a/src/effects/SkLayerDrawLooper.cpp
+++ b/src/effects/SkLayerDrawLooper.cpp
@@ -64,15 +64,18 @@
}
}
+// Even with kEntirePaint_Bits, we always ensure that the master paint's
+// text-encoding is respected, since that controls how we interpret the
+// text/length parameters of a draw[Pos]Text call.
void SkLayerDrawLooper::ApplyInfo(SkPaint* dst, const SkPaint& src,
const LayerInfo& info) {
uint32_t mask = info.fFlagsMask;
dst->setFlags((dst->getFlags() & ~mask) | (src.getFlags() & mask));
-
dst->setColor(xferColor(src.getColor(), dst->getColor(), info.fColorMode));
BitFlags bits = info.fPaintBits;
+ SkPaint::TextEncoding encoding = dst->getTextEncoding();
if (0 == bits) {
return;
@@ -84,6 +87,7 @@
*dst = src;
dst->setFlags(f);
dst->setColor(c);
+ dst->setTextEncoding(encoding);
return;
}