| Index: skia/ext/analysis_canvas.cc
|
| diff --git a/skia/ext/analysis_canvas.cc b/skia/ext/analysis_canvas.cc
|
| index 72b9eeb987bdc07adf74c3a2f6b0f5cdbe5b6faf..54e1b77694a927d941a8d9cbfbbdc67ba1f8c196 100644
|
| --- a/skia/ext/analysis_canvas.cc
|
| +++ b/skia/ext/analysis_canvas.cc
|
| @@ -7,6 +7,7 @@
|
| #include "third_party/skia/include/core/SkDevice.h"
|
| #include "third_party/skia/include/core/SkDraw.h"
|
| #include "third_party/skia/include/core/SkRRect.h"
|
| +#include "third_party/skia/src/core/SkRasterClip.h"
|
| #include "ui/gfx/rect_conversions.h"
|
|
|
| namespace {
|
| @@ -16,13 +17,61 @@ namespace {
|
| // 25x as long as Z620.
|
| const int gPictureCostThreshold = 1000;
|
|
|
| +static bool isSolidColorPaint(const SkPaint& paint) {
|
| + SkXfermode::Mode xferMode;
|
| +
|
| + // getXfermode can return a NULL, but that is handled
|
| + // gracefully by AsMode (NULL turns into kSrcOver mode).
|
| + SkXfermode::AsMode(paint.getXfermode(), &xferMode);
|
| +
|
| + // Paint is solid color if the following holds:
|
| + // - Alpha is 1.0, style is fill, and there are no special effects
|
| + // - Xfer mode is either kSrc or kSrcOver (kSrcOver is equivalent
|
| + // to kSrc if source alpha is 1.0, which is already checked).
|
| + return (paint.getAlpha() == 255 &&
|
| + !paint.getShader() &&
|
| + !paint.getLooper() &&
|
| + !paint.getMaskFilter() &&
|
| + !paint.getColorFilter() &&
|
| + paint.getStyle() == SkPaint::kFill_Style &&
|
| + (xferMode == SkXfermode::kSrc_Mode ||
|
| + xferMode == SkXfermode::kSrcOver_Mode));
|
| }
|
|
|
| +static bool isFullQuad(const SkDraw& draw,
|
| + const SkRect& canvasRect,
|
| + const SkRect& drawnRect) {
|
| + SkRect drawBitmapRect;
|
| + draw.fBitmap->getBounds(&drawBitmapRect);
|
| + SkRect clipRect = SkRect::Make(draw.fRC->getBounds());
|
| + SkRect deviceRect;
|
| + draw.fMatrix->mapRect(&deviceRect, drawnRect);
|
| +
|
| + // The drawn rect covers the full canvas, if the following conditions hold:
|
| + // - Clip rect is an actual rectangle.
|
| + // - The rect we're drawing (post-transform) contains the clip rect.
|
| + // That is, all of clip rect will be colored by the rect.
|
| + // - Clip rect contains the canvas rect.
|
| + // That is, we're not clipping to a portion of this canvas.
|
| + // - The bitmap into which the draw call happens is at least as
|
| + // big as the canvas rect
|
| + return draw.fRC->isRect() &&
|
| + deviceRect.contains(clipRect) &&
|
| + clipRect.contains(canvasRect) &&
|
| + drawBitmapRect.contains(canvasRect);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| namespace skia {
|
|
|
| AnalysisDevice::AnalysisDevice(const SkBitmap& bm)
|
| : INHERITED(bm)
|
| - , estimatedCost_(0) {
|
| + , estimatedCost_(0)
|
| + , isForcedNotSolid_(false)
|
| + , isForcedNotTransparent_(false)
|
| + , isSolidColor_(false)
|
| + , isTransparent_(false) {
|
|
|
| }
|
|
|
| @@ -34,32 +83,112 @@ int AnalysisDevice::getEstimatedCost() const {
|
| return estimatedCost_;
|
| }
|
|
|
| +bool AnalysisDevice::getColorIfSolid(SkColor* color) const {
|
| + if (isSolidColor_)
|
| + *color = color_;
|
| + return isSolidColor_;
|
| +}
|
| +
|
| +bool AnalysisDevice::isTransparent() const {
|
| + return isTransparent_;
|
| +}
|
| +
|
| +void AnalysisDevice::setForceNotSolid(bool flag) {
|
| + isForcedNotSolid_ = flag;
|
| + if (isForcedNotSolid_)
|
| + isSolidColor_ = false;
|
| +}
|
| +
|
| +void AnalysisDevice::setForceNotTransparent(bool flag) {
|
| + isForcedNotTransparent_ = flag;
|
| + if (isForcedNotTransparent_)
|
| + isTransparent_ = false;
|
| +}
|
| +
|
| void AnalysisDevice::clear(SkColor color) {
|
| - ++estimatedCost_;
|
| + ++estimatedCost_;
|
| +
|
| + isTransparent_ = (!isForcedNotTransparent_ && SkColorGetA(color) == 0);
|
| +
|
| + if (!isForcedNotSolid_ && SkColorGetA(color) == 255) {
|
| + isSolidColor_ = true;
|
| + color_ = color;
|
| + }
|
| + else {
|
| + isSolidColor_ = false;
|
| + }
|
| }
|
|
|
| void AnalysisDevice::drawPaint(const SkDraw&, const SkPaint& paint) {
|
| ++estimatedCost_;
|
| + isSolidColor_ = false;
|
| + isTransparent_ = false;
|
| }
|
|
|
| void AnalysisDevice::drawPoints(const SkDraw&, SkCanvas::PointMode mode,
|
| size_t count, const SkPoint[],
|
| const SkPaint& paint) {
|
| ++estimatedCost_;
|
| + isSolidColor_ = false;
|
| + isTransparent_ = false;
|
| }
|
|
|
| -void AnalysisDevice::drawRect(const SkDraw&, const SkRect& r,
|
| +void AnalysisDevice::drawRect(const SkDraw& draw, const SkRect& rect,
|
| const SkPaint& paint) {
|
| +
|
| // FIXME: if there's a pending image decode & resize, more expensive
|
| if (paint.getMaskFilter()) {
|
| estimatedCost_ += 300;
|
| }
|
| ++estimatedCost_;
|
| +
|
| + bool doesCoverCanvas = isFullQuad(draw,
|
| + SkRect::MakeWH(width(), height()),
|
| + rect);
|
| +
|
| + SkXfermode::Mode xferMode;
|
| + SkXfermode::AsMode(paint.getXfermode(), &xferMode);
|
| +
|
| + // This canvas will become transparent if the following holds:
|
| + // - The quad is a full tile quad
|
| + // - We're not in "forced not transparent" mode
|
| + // - Transfer mode is clear (0 color, 0 alpha)
|
| + //
|
| + // If the paint alpha is not 0, or if the transfrer mode is
|
| + // not src, then this canvas will not be transparent.
|
| + //
|
| + // In all other cases, we keep the current transparent value
|
| + if (doesCoverCanvas &&
|
| + !isForcedNotTransparent_ &&
|
| + xferMode == SkXfermode::kClear_Mode) {
|
| + isTransparent_ = true;
|
| + }
|
| + else if (paint.getAlpha() != 0 ||
|
| + xferMode != SkXfermode::kSrc_Mode) {
|
| + isTransparent_ = false;
|
| + }
|
| +
|
| + // This bitmap is solid if and only if the following holds.
|
| + // Note that this might be overly conservative:
|
| + // - We're not in "forced not solid" mode
|
| + // - Paint is solid color
|
| + // - The quad is a full tile quad
|
| + if (!isForcedNotSolid_ &&
|
| + isSolidColorPaint(paint) &&
|
| + doesCoverCanvas) {
|
| + isSolidColor_ = true;
|
| + color_ = paint.getColor();
|
| + }
|
| + else {
|
| + isSolidColor_ = false;
|
| + }
|
| }
|
|
|
| void AnalysisDevice::drawOval(const SkDraw&, const SkRect& oval,
|
| const SkPaint& paint) {
|
| ++estimatedCost_;
|
| + isSolidColor_ = false;
|
| + isTransparent_ = false;
|
| }
|
|
|
| void AnalysisDevice::drawPath(const SkDraw&, const SkPath& path,
|
| @@ -73,31 +202,42 @@ void AnalysisDevice::drawPath(const SkDraw&, const SkPath& path,
|
| estimatedCost_ += 300;
|
| }
|
| ++estimatedCost_;
|
| + isSolidColor_ = false;
|
| + isTransparent_ = false;
|
| }
|
|
|
| void AnalysisDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap,
|
| const SkIRect* srcRectOrNull,
|
| - const SkMatrix& matrix, const SkPaint& paint)
|
| - {
|
| + const SkMatrix& matrix, const SkPaint& paint) {
|
| ++estimatedCost_;
|
| + isSolidColor_ = false;
|
| + isTransparent_ = false;
|
| }
|
|
|
| void AnalysisDevice::drawSprite(const SkDraw&, const SkBitmap& bitmap,
|
| int x, int y, const SkPaint& paint) {
|
| ++estimatedCost_;
|
| + isSolidColor_ = false;
|
| + isTransparent_ = false;
|
| }
|
|
|
| -void AnalysisDevice::drawBitmapRect(const SkDraw&, const SkBitmap&,
|
| +void AnalysisDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap&,
|
| const SkRect* srcOrNull, const SkRect& dst,
|
| const SkPaint& paint) {
|
| ++estimatedCost_;
|
| +
|
| + // Call drawRect to determine transparency,
|
| + // but reset solid color to false.
|
| + drawRect(draw, dst, paint);
|
| + isSolidColor_ = false;
|
| }
|
|
|
|
|
| void AnalysisDevice::drawText(const SkDraw&, const void* text, size_t len,
|
| - SkScalar x, SkScalar y, const SkPaint& paint)
|
| - {
|
| + SkScalar x, SkScalar y, const SkPaint& paint) {
|
| ++estimatedCost_;
|
| + isSolidColor_ = false;
|
| + isTransparent_ = false;
|
| }
|
|
|
| void AnalysisDevice::drawPosText(const SkDraw& draw, const void* text, size_t len,
|
| @@ -106,21 +246,26 @@ void AnalysisDevice::drawPosText(const SkDraw& draw, const void* text, size_t le
|
| // FIXME: On Z620, every glyph cache miss costs us about 10us.
|
| // We don't have a good mechanism for predicting glyph cache misses.
|
| ++estimatedCost_;
|
| + isSolidColor_ = false;
|
| + isTransparent_ = false;
|
| }
|
|
|
| void AnalysisDevice::drawTextOnPath(const SkDraw&, const void* text, size_t len,
|
| const SkPath& path, const SkMatrix* matrix,
|
| const SkPaint& paint) {
|
| ++estimatedCost_;
|
| + isSolidColor_ = false;
|
| + isTransparent_ = false;
|
| }
|
|
|
| #ifdef SK_BUILD_FOR_ANDROID
|
| void AnalysisDevice::drawPosTextOnPath(const SkDraw& draw, const void* text,
|
| size_t len,
|
| const SkPoint pos[], const SkPaint& paint,
|
| - const SkPath& path, const SkMatrix* matrix)
|
| - {
|
| + const SkPath& path, const SkMatrix* matrix) {
|
| ++estimatedCost_;
|
| + isSolidColor_ = false;
|
| + isTransparent_ = false;
|
| }
|
| #endif
|
|
|
| @@ -131,19 +276,22 @@ void AnalysisDevice::drawVertices(const SkDraw&, SkCanvas::VertexMode,
|
| const uint16_t indices[], int indexCount,
|
| const SkPaint& paint) {
|
| ++estimatedCost_;
|
| + isSolidColor_ = false;
|
| + isTransparent_ = false;
|
| }
|
|
|
| void AnalysisDevice::drawDevice(const SkDraw&, SkDevice*, int x, int y,
|
| const SkPaint&) {
|
| ++estimatedCost_;
|
| + isSolidColor_ = false;
|
| + isTransparent_ = false;
|
| }
|
|
|
|
|
|
|
| -
|
| AnalysisCanvas::AnalysisCanvas(AnalysisDevice* device)
|
| - : INHERITED(device) {
|
| -
|
| + : INHERITED(device)
|
| + , savedLayerStackSize_(0) {
|
| }
|
|
|
| AnalysisCanvas::~AnalysisCanvas() {
|
| @@ -154,11 +302,18 @@ bool AnalysisCanvas::isCheap() const {
|
| return getEstimatedCost() < gPictureCostThreshold;
|
| }
|
|
|
| +bool AnalysisCanvas::getColorIfSolid(SkColor* color) const {
|
| + return (static_cast<AnalysisDevice*>(getDevice()))->getColorIfSolid(color);
|
| +}
|
| +
|
| +bool AnalysisCanvas::isTransparent() const {
|
| + return (static_cast<AnalysisDevice*>(getDevice()))->isTransparent();
|
| +}
|
| +
|
| int AnalysisCanvas::getEstimatedCost() const {
|
| return (static_cast<AnalysisDevice*>(getDevice()))->getEstimatedCost();
|
| }
|
|
|
| -
|
| bool AnalysisCanvas::clipRect(const SkRect& rect, SkRegion::Op op,
|
| bool doAA) {
|
| return INHERITED::clipRect(rect, op, doAA);
|
| @@ -174,17 +329,49 @@ bool AnalysisCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op,
|
| return INHERITED::clipRect(rrect.getBounds(), op, doAA);
|
| }
|
|
|
| -int AnalysisCanvas::saveLayer(const SkRect* bounds, const SkPaint*,
|
| +int AnalysisCanvas::save(SkCanvas::SaveFlags flags) {
|
| + INHERITED::save(flags);
|
| +}
|
| +
|
| +int AnalysisCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
|
| SkCanvas::SaveFlags flags) {
|
| + // If after we draw to the saved layer, we have to blend with the current
|
| + // layer, then we can conservatively say that the canvas will not be of
|
| + // solid color.
|
| + if ((paint && !isSolidColorPaint(*paint)) ||
|
| + (bounds && !bounds->contains(
|
| + SkRect::MakeWH(getDevice()->width(), getDevice()->height()))))
|
| + (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(true);
|
| +
|
| + // If after we draw to the save layer, we have to blend with the current
|
| + // layer using any part of the current layer's alpha, then we can
|
| + // conservatively say that the canvas will not be transparent.
|
| + SkXfermode::Mode xferMode = SkXfermode::kSrc_Mode;
|
| + if (paint)
|
| + SkXfermode::AsMode(paint->getXfermode(), &xferMode);
|
| + if (xferMode != SkXfermode::kSrc_Mode)
|
| + (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(true);
|
| +
|
| + ++savedLayerStackSize_;
|
| +
|
| // Actually saving a layer here could cause a new bitmap to be created
|
| // and real rendering to occur.
|
| - int count = SkCanvas::save(flags);
|
| + int count = INHERITED::save(flags);
|
| if (bounds) {
|
| INHERITED::clipRectBounds(bounds, flags, NULL);
|
| }
|
| return count;
|
| }
|
|
|
| +void AnalysisCanvas::restore() {
|
| + INHERITED::restore();
|
| +
|
| + if (--savedLayerStackSize_ == 0) {
|
| + (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(false);
|
| + (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(false);
|
| + }
|
| +}
|
| +
|
| } // namespace skia
|
|
|
|
|
|
|