summaryrefslogtreecommitdiffstats
path: root/skia
diff options
context:
space:
mode:
authorvmpstr@chromium.org <vmpstr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-07 23:52:24 +0000
committervmpstr@chromium.org <vmpstr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-07 23:52:24 +0000
commit785145baf07145f8dc412fc6aa3e48851181d353 (patch)
tree6cb02ca0f5cb0469eabc744d6c34b8b09ff772b2 /skia
parent876395c1e0a01c3889b0605d4779a772215e74de (diff)
downloadchromium_src-785145baf07145f8dc412fc6aa3e48851181d353.zip
chromium_src-785145baf07145f8dc412fc6aa3e48851181d353.tar.gz
chromium_src-785145baf07145f8dc412fc6aa3e48851181d353.tar.bz2
cc: Consolidate the analysis_canvas operations
This patch combines predictions (color, transparency, and cheapness) into one processing step. Also adds code to use color and transparency information. BUG=179548 Review URL: https://chromiumcodereview.appspot.com/12316084 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@186819 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'skia')
-rw-r--r--skia/ext/analysis_canvas.cc269
-rw-r--r--skia/ext/analysis_canvas.h22
-rw-r--r--skia/ext/analysis_canvas_unittest.cc313
3 files changed, 588 insertions, 16 deletions
diff --git a/skia/ext/analysis_canvas.cc b/skia/ext/analysis_canvas.cc
index 72b9eeb..2a2c7f3 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,67 @@ 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) {
+
+ // If the transform results in a non-axis aligned
+ // rect, then be conservative and return false.
+ if (!draw.fMatrix->rectStaysRect())
+ return false;
+
+ 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 +89,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 +208,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 +252,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 +282,25 @@ 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;
}
-
+const int AnalysisCanvas::kNoLayer = -1;
AnalysisCanvas::AnalysisCanvas(AnalysisDevice* device)
- : INHERITED(device) {
-
+ : INHERITED(device)
+ , savedStackSize_(0)
+ , forceNotSolidStackLevel_(kNoLayer)
+ , forceNotTransparentStackLevel_(kNoLayer) {
}
AnalysisCanvas::~AnalysisCanvas() {
@@ -154,11 +311,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);
@@ -166,25 +330,98 @@ bool AnalysisCanvas::clipRect(const SkRect& rect, SkRegion::Op op,
bool AnalysisCanvas::clipPath(const SkPath& path, SkRegion::Op op,
bool doAA) {
+ // clipPaths can make our calls to isFullQuad invalid (ie have false
+ // positives). As a precaution, force the setting to be non-solid
+ // and non-transparent until we pop this
+ if (forceNotSolidStackLevel_ == kNoLayer) {
+ forceNotSolidStackLevel_ = savedStackSize_;
+ (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(true);
+ }
+ if (forceNotTransparentStackLevel_ == kNoLayer) {
+ forceNotTransparentStackLevel_ = savedStackSize_;
+ (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(true);
+ }
+
return INHERITED::clipRect(path.getBounds(), op, doAA);
}
bool AnalysisCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op,
bool doAA) {
+ // clipRRect can make our calls to isFullQuad invalid (ie have false
+ // positives). As a precaution, force the setting to be non-solid
+ // and non-transparent until we pop this
+ if (forceNotSolidStackLevel_ == kNoLayer) {
+ forceNotSolidStackLevel_ = savedStackSize_;
+ (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(true);
+ }
+ if (forceNotTransparentStackLevel_ == kNoLayer) {
+ forceNotTransparentStackLevel_ = savedStackSize_;
+ (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(true);
+ }
+
return INHERITED::clipRect(rrect.getBounds(), op, doAA);
}
-int AnalysisCanvas::saveLayer(const SkRect* bounds, const SkPaint*,
+int AnalysisCanvas::save(SkCanvas::SaveFlags flags) {
+ ++savedStackSize_;
+ return INHERITED::save(flags);
+}
+
+int AnalysisCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
SkCanvas::SaveFlags flags) {
+ ++savedStackSize_;
+
+ // 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())))) {
+ if (forceNotSolidStackLevel_ == kNoLayer) {
+ forceNotSolidStackLevel_ = savedStackSize_;
+ (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) {
+ if (forceNotTransparentStackLevel_ == kNoLayer) {
+ forceNotTransparentStackLevel_ = savedStackSize_;
+ (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(true);
+ }
+ }
+
// 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();
+
+ DCHECK(savedStackSize_);
+ if (savedStackSize_) {
+ --savedStackSize_;
+ if (savedStackSize_ < forceNotSolidStackLevel_) {
+ (static_cast<AnalysisDevice*>(getDevice()))->setForceNotSolid(false);
+ forceNotSolidStackLevel_ = kNoLayer;
+ }
+ if (savedStackSize_ < forceNotTransparentStackLevel_) {
+ (static_cast<AnalysisDevice*>(getDevice()))->setForceNotTransparent(false);
+ forceNotTransparentStackLevel_ = kNoLayer;
+ }
+ }
+}
+
} // namespace skia
diff --git a/skia/ext/analysis_canvas.h b/skia/ext/analysis_canvas.h
index e2eedd2..fd7ee25 100644
--- a/skia/ext/analysis_canvas.h
+++ b/skia/ext/analysis_canvas.h
@@ -26,6 +26,8 @@ class SK_API AnalysisCanvas : public SkCanvas {
// Returns true if the estimated cost of drawing is below an
// arbitrary threshold.
bool isCheap() const;
+ bool getColorIfSolid(SkColor* color) const;
+ bool isTransparent() const;
// Returns the estimated cost of drawing, in arbitrary units.
int getEstimatedCost() const;
@@ -42,8 +44,17 @@ class SK_API AnalysisCanvas : public SkCanvas {
virtual int saveLayer(const SkRect* bounds, const SkPaint*,
SkCanvas::SaveFlags flags) OVERRIDE;
+ virtual int save(SaveFlags flags = kMatrixClip_SaveFlag) OVERRIDE;
+
+ virtual void restore() OVERRIDE;
+
private:
typedef SkCanvas INHERITED;
+ static const int kNoLayer;
+
+ int savedStackSize_;
+ int forceNotSolidStackLevel_;
+ int forceNotTransparentStackLevel_;
};
class SK_API AnalysisDevice : public SkDevice {
@@ -52,6 +63,11 @@ class SK_API AnalysisDevice : public SkDevice {
virtual ~AnalysisDevice();
int getEstimatedCost() const;
+ bool getColorIfSolid(SkColor* color) const;
+ bool isTransparent() const;
+
+ void setForceNotSolid(bool flag);
+ void setForceNotTransparent(bool flag);
protected:
virtual void clear(SkColor color) OVERRIDE;
@@ -105,6 +121,12 @@ class SK_API AnalysisDevice : public SkDevice {
private:
typedef SkDevice INHERITED;
+
+ bool isForcedNotSolid_;
+ bool isForcedNotTransparent_;
+ bool isSolidColor_;
+ SkColor color_;
+ bool isTransparent_;
};
} // namespace skia
diff --git a/skia/ext/analysis_canvas_unittest.cc b/skia/ext/analysis_canvas_unittest.cc
new file mode 100644
index 0000000..17cfcb5
--- /dev/null
+++ b/skia/ext/analysis_canvas_unittest.cc
@@ -0,0 +1,313 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/compiler_specific.h"
+#include "skia/ext/analysis_canvas.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+void solidColorFill(skia::AnalysisCanvas& canvas) {
+ canvas.clear(SkColorSetARGB(255, 255, 255, 255));
+}
+
+void transparentFill(skia::AnalysisCanvas& canvas) {
+ canvas.clear(SkColorSetARGB(0, 0, 0, 0));
+}
+
+} // namespace
+namespace skia {
+
+TEST(AnalysisCanvasTest, EmptyCanvas) {
+ SkBitmap emptyBitmap;
+ emptyBitmap.setConfig(SkBitmap::kNo_Config, 255, 255);
+ skia::AnalysisDevice device(emptyBitmap);
+ skia::AnalysisCanvas canvas(&device);
+
+ SkColor color;
+ EXPECT_FALSE(canvas.getColorIfSolid(&color));
+ EXPECT_FALSE(canvas.isTransparent());
+ EXPECT_TRUE(canvas.isCheap());
+}
+
+TEST(AnalysisCanvasTest, ClearCanvas) {
+ SkBitmap emptyBitmap;
+ emptyBitmap.setConfig(SkBitmap::kNo_Config, 255, 255);
+ skia::AnalysisDevice device(emptyBitmap);
+ skia::AnalysisCanvas canvas(&device);
+
+ // Transparent color
+ SkColor color = SkColorSetARGB(0, 12, 34, 56);
+ canvas.clear(color);
+
+ SkColor outputColor;
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_TRUE(canvas.isTransparent());
+ EXPECT_TRUE(canvas.isCheap());
+
+ // Solid color
+ color = SkColorSetARGB(255, 65, 43, 21);
+ canvas.clear(color);
+
+ EXPECT_TRUE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+ EXPECT_TRUE(canvas.isCheap());
+ EXPECT_EQ(outputColor, color);
+
+ // Translucent color
+ color = SkColorSetARGB(128, 11, 22, 33);
+ canvas.clear(color);
+
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+ EXPECT_TRUE(canvas.isCheap());
+
+ // Test helper methods
+ solidColorFill(canvas);
+ EXPECT_TRUE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+
+ transparentFill(canvas);
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_TRUE(canvas.isTransparent());
+}
+
+TEST(AnalysisCanvasTest, ComplexActions) {
+ SkBitmap emptyBitmap;
+ emptyBitmap.setConfig(SkBitmap::kNo_Config, 255, 255);
+ skia::AnalysisDevice device(emptyBitmap);
+ skia::AnalysisCanvas canvas(&device);
+
+ // Draw paint test.
+ SkColor color = SkColorSetARGB(255, 11, 22, 33);
+ SkPaint paint;
+ paint.setColor(color);
+
+ canvas.drawPaint(paint);
+
+ SkColor outputColor;
+ //TODO(vmpstr): This should return true. (crbug.com/180597)
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+ EXPECT_TRUE(canvas.isCheap());
+
+ // Draw points test.
+ SkPoint points[4] = {
+ SkPoint::Make(0, 0),
+ SkPoint::Make(255, 0),
+ SkPoint::Make(255, 255),
+ SkPoint::Make(0, 255)
+ };
+
+ solidColorFill(canvas);
+ canvas.drawPoints(SkCanvas::kLines_PointMode, 4, points, paint);
+
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+ EXPECT_TRUE(canvas.isCheap());
+
+ // Draw oval test.
+ solidColorFill(canvas);
+ canvas.drawOval(SkRect::MakeWH(255, 255), paint);
+
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+ EXPECT_TRUE(canvas.isCheap());
+
+ // Draw bitmap test.
+ solidColorFill(canvas);
+ SkBitmap secondBitmap;
+ secondBitmap.setConfig(SkBitmap::kNo_Config, 255, 255);
+ canvas.drawBitmap(secondBitmap, 0, 0);
+
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+ EXPECT_TRUE(canvas.isCheap());
+}
+
+TEST(AnalysisCanvasTest, SimpleDrawRect) {
+ SkBitmap emptyBitmap;
+ emptyBitmap.setConfig(SkBitmap::kNo_Config, 255, 255);
+ skia::AnalysisDevice device(emptyBitmap);
+ skia::AnalysisCanvas canvas(&device);
+
+ SkColor color = SkColorSetARGB(255, 11, 22, 33);
+ SkPaint paint;
+ paint.setColor(color);
+ canvas.clipRect(SkRect::MakeWH(255, 255));
+ canvas.drawRect(SkRect::MakeWH(255, 255), paint);
+
+ SkColor outputColor;
+ EXPECT_TRUE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+ EXPECT_TRUE(canvas.isCheap());
+ EXPECT_EQ(color, outputColor);
+
+ color = SkColorSetARGB(255, 22, 33, 44);
+ paint.setColor(color);
+ canvas.translate(-128, -128);
+ canvas.drawRect(SkRect::MakeWH(382, 382), paint);
+
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+ EXPECT_TRUE(canvas.isCheap());
+
+ color = SkColorSetARGB(255, 33, 44, 55);
+ paint.setColor(color);
+ canvas.drawRect(SkRect::MakeWH(383, 383), paint);
+
+ EXPECT_TRUE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+ EXPECT_TRUE(canvas.isCheap());
+ EXPECT_EQ(color, outputColor);
+
+ color = SkColorSetARGB(0, 0, 0, 0);
+ paint.setColor(color);
+ canvas.drawRect(SkRect::MakeWH(383, 383), paint);
+
+ EXPECT_TRUE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+ EXPECT_TRUE(canvas.isCheap());
+ EXPECT_EQ(outputColor, SkColorSetARGB(255, 33, 44, 55));
+
+ color = SkColorSetARGB(128, 128, 128, 128);
+ paint.setColor(color);
+ canvas.drawRect(SkRect::MakeWH(383, 383), paint);
+
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+ EXPECT_TRUE(canvas.isCheap());
+
+ paint.setXfermodeMode(SkXfermode::kClear_Mode);
+ canvas.drawRect(SkRect::MakeWH(382, 382), paint);
+
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+ EXPECT_TRUE(canvas.isCheap());
+
+ canvas.drawRect(SkRect::MakeWH(383, 383), paint);
+
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_TRUE(canvas.isTransparent());
+ EXPECT_TRUE(canvas.isCheap());
+
+ canvas.translate(128, 128);
+ color = SkColorSetARGB(255, 11, 22, 33);
+ paint.setColor(color);
+ paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
+ canvas.drawRect(SkRect::MakeWH(255, 255), paint);
+
+ EXPECT_TRUE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+ EXPECT_TRUE(canvas.isCheap());
+ EXPECT_EQ(color, outputColor);
+
+ canvas.rotate(50);
+ canvas.drawRect(SkRect::MakeWH(255, 255), paint);
+
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+ EXPECT_TRUE(canvas.isCheap());
+}
+
+TEST(AnalysisCanvasTest, ClipPath) {
+ SkBitmap emptyBitmap;
+ emptyBitmap.setConfig(SkBitmap::kNo_Config, 255, 255);
+ skia::AnalysisDevice device(emptyBitmap);
+ skia::AnalysisCanvas canvas(&device);
+
+ SkPath path;
+ path.moveTo(0, 0);
+ path.lineTo(255, 0);
+ path.lineTo(255, 255);
+ path.lineTo(0, 255);
+
+ SkColor outputColor;
+ solidColorFill(canvas);
+ canvas.clipPath(path);
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+
+ canvas.save();
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+
+ canvas.clipPath(path);
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+
+ canvas.restore();
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+
+ solidColorFill(canvas);
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+}
+
+TEST(AnalysisCanvasTest, SaveLayerRestore) {
+ SkBitmap emptyBitmap;
+ emptyBitmap.setConfig(SkBitmap::kNo_Config, 255, 255);
+ skia::AnalysisDevice device(emptyBitmap);
+ skia::AnalysisCanvas canvas(&device);
+
+ SkColor outputColor;
+ solidColorFill(canvas);
+ EXPECT_TRUE(canvas.getColorIfSolid(&outputColor));
+
+ SkRect bounds = SkRect::MakeWH(255, 255);
+ SkPaint paint;
+ paint.setColor(SkColorSetARGB(255, 255, 255, 255));
+ paint.setXfermodeMode(SkXfermode::kSrcOver_Mode);
+
+ // This should force non-transparency
+ canvas.saveLayer(&bounds, &paint, SkCanvas::kMatrix_SaveFlag);
+ EXPECT_TRUE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+
+ transparentFill(canvas);
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+
+ solidColorFill(canvas);
+ EXPECT_TRUE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+
+ paint.setXfermodeMode(SkXfermode::kDst_Mode);
+
+ // This should force non-solid color
+ canvas.saveLayer(&bounds, &paint, SkCanvas::kMatrix_SaveFlag);
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+
+ transparentFill(canvas);
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+
+ solidColorFill(canvas);
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+
+ canvas.restore();
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+
+ transparentFill(canvas);
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+
+ solidColorFill(canvas);
+ EXPECT_TRUE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+
+ canvas.restore();
+ EXPECT_TRUE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+
+ transparentFill(canvas);
+ EXPECT_FALSE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_TRUE(canvas.isTransparent());
+
+ solidColorFill(canvas);
+ EXPECT_TRUE(canvas.getColorIfSolid(&outputColor));
+ EXPECT_FALSE(canvas.isTransparent());
+}
+
+} // namespace skia