Index: Source/platform/graphics/GraphicsContextTest.cpp |
diff --git a/Source/platform/graphics/GraphicsContextTest.cpp b/Source/platform/graphics/GraphicsContextTest.cpp |
index fe8b95e939a8b6b9ff9302c82b5914cec334658a..a911387f56d01d41d30778e7d6e521ed747147d2 100644 |
--- a/Source/platform/graphics/GraphicsContextTest.cpp |
+++ b/Source/platform/graphics/GraphicsContextTest.cpp |
@@ -66,6 +66,17 @@ namespace { |
} \ |
} |
+#define EXPECT_PIXELS_MATCH_COLOR(bitmap, rect, color) \ |
+{ \ |
+ SkAutoLockPixels locker(bitmap); \ |
+ for (int y = rect.y(); y < rect.maxY(); ++y) { \ |
+ for (int x = rect.x(); x < rect.maxX(); ++x) { \ |
+ RGBA32 pixel = *bitmap.getAddr32(x, y); \ |
+ EXPECT_EQ(color, pixel); \ |
+ } \ |
+ } \ |
+} |
+ |
TEST(GraphicsContextTest, trackOpaqueTest) |
{ |
SkBitmap bitmap; |
@@ -1214,4 +1225,156 @@ TEST(GraphicsContextTest, RecordingCanvas) |
context.endRecording(); |
} |
+TEST(GraphicsContextTest, BeginLayerDontAffectCanvasState) |
+{ |
+ SkBitmap bitmap; |
+ bitmap.allocN32Pixels(1, 1); |
+ bitmap.eraseColor(0); |
+ SkCanvas canvas(bitmap); |
+ GraphicsContext context(&canvas); |
+ |
+ IntRect rect(0, 0, 1, 1); |
+ EXPECT_PIXELS_MATCH_COLOR(bitmap, rect, Color::transparent); |
+ context.fillRect(rect, Color::gray); |
+ EXPECT_PIXELS_MATCH_COLOR(bitmap, rect, Color::gray); |
+ |
+ // Translate out of bound not to draw. |
+ context.translate(1, 0); |
+ context.fillRect(rect, Color::darkGray); |
+ EXPECT_PIXELS_MATCH_COLOR(bitmap, rect, Color::gray); |
+ EXPECT_EQ(SK_Scalar1, context.getTotalMatrix().getTranslateX()); |
+ |
+ context.beginLayer(1, CompositeSourceOver); |
+ context.translate(-1, 0); |
+ EXPECT_EQ(0, context.getTotalMatrix().getTranslateX()); |
+ context.fillRect(rect, Color::darkGray); |
+ context.endLayer(); |
+ EXPECT_PIXELS_MATCH_COLOR(bitmap, rect, Color::darkGray); |
+ |
+ // GraphicsContext::endLayer() must preserve current states. |
+ EXPECT_EQ(0, context.getTotalMatrix().getTranslateX()); |
+ |
+ context.fillRect(rect, Color::lightGray); |
+ EXPECT_PIXELS_MATCH_COLOR(bitmap, rect, Color::lightGray); |
+} |
+ |
+// Although this test looks like duplicated to BeginLayerPreserveCanvasState, |
+// this is needed because GraphicsContext keeps a composite operator in SkPaint |
+// while setting a transform to SkCanvas directly. |
+TEST(GraphicsContextTest, BeginLayerDontAffectPaintState) |
+{ |
+ SkBitmap bitmap; |
+ bitmap.allocN32Pixels(1, 1); |
+ bitmap.eraseColor(0); |
+ SkCanvas canvas(bitmap); |
+ GraphicsContext context(&canvas); |
+ |
+ IntRect rect(0, 0, 1, 1); |
+ EXPECT_PIXELS_MATCH_COLOR(bitmap, rect, Color::transparent); |
+ EXPECT_EQ(CompositeSourceOver, context.compositeOperation()); |
+ context.fillRect(rect, Color::gray); |
+ EXPECT_PIXELS_MATCH_COLOR(bitmap, rect, Color::gray); |
+ |
+ // Set CompositeDestinationIn not to draw. |
+ context.setCompositeOperation(CompositeDestinationIn); |
+ context.fillRect(rect, Color::darkGray); |
+ EXPECT_PIXELS_MATCH_COLOR(bitmap, rect, Color::gray); |
+ EXPECT_EQ(CompositeDestinationIn, context.compositeOperation()); |
+ |
+ context.beginLayer(1, CompositeSourceIn); |
+ EXPECT_EQ(CompositeDestinationIn, context.compositeOperation()); |
+ context.setCompositeOperation(CompositeSourceOver); |
+ EXPECT_EQ(CompositeSourceOver, context.compositeOperation()); |
+ context.fillRect(rect, Color::darkGray); |
+ context.endLayer(); |
+ EXPECT_PIXELS_MATCH_COLOR(bitmap, rect, Color::darkGray); |
+ |
+ // GraphicsContext::endLayer() must preserve current states. |
+ EXPECT_EQ(CompositeSourceOver, context.compositeOperation()); |
+ |
+ context.fillRect(rect, Color::lightGray); |
+ EXPECT_PIXELS_MATCH_COLOR(bitmap, rect, Color::lightGray); |
+} |
+ |
+// Cannot reuse SkClipStack::Element::operator==() because it checks save count. |
+bool equal(const SkClipStack::Element* a, const SkClipStack::Element* b) |
+{ |
+ if (a->getOp() != b->getOp() || a->getType() != b->getType() || a->isAA() != b->isAA()) { |
+ return false; |
+ } |
+ switch (a->getType()) { |
+ case SkClipStack::Element::kPath_Type: |
+ return a->getPath() == b->getPath(); |
+ case SkClipStack::Element::kRRect_Type: |
+ return a->getRRect() == b->getRRect(); |
+ case SkClipStack::Element::kRect_Type: |
+ return a->getRect() == b->getRect(); |
+ case SkClipStack::Element::kEmpty_Type: |
+ return true; |
+ default: |
+ ASSERT_NOT_REACHED(); |
+ return false; |
+ } |
+} |
+ |
+// Cannot reuse SkClipStack::operator==() because it checks save count. |
+bool equal(const SkClipStack* a, const SkClipStack* b) |
+{ |
+ SkClipStack::B2TIter aIter(*a); |
+ SkClipStack::B2TIter bIter(*b); |
+ const SkClipStack::Element* aElement = aIter.next(); |
+ const SkClipStack::Element* bElement = bIter.next(); |
+ |
+ while (aElement && bElement) { |
+ if (!equal(aElement, bElement)) { |
+ return false; |
+ } |
+ aElement = aIter.next(); |
+ bElement = bIter.next(); |
+ } |
+ return !aElement && !bElement; |
+} |
+ |
+TEST(GraphicsContextTest, BeginLayerDontAffectClipState) |
+{ |
+ SkBitmap bitmap; |
+ bitmap.allocN32Pixels(10, 10); |
+ bitmap.eraseColor(0); |
+ SkCanvas canvas(bitmap); |
+ GraphicsContext context(&canvas); |
+ // Reference to compare clip stack. It's needed because SkCanvas::saveLayer() can perform an additional clip op. |
+ SkBitmap bitmapRef; |
+ bitmapRef.allocN32Pixels(10, 10); |
+ bitmapRef.eraseColor(0); |
+ SkCanvas canvasRef(bitmapRef); |
+ GraphicsContext contextRef(&canvasRef); |
+ |
+ context.clip(IntRect(1, 1, 9, 9)); |
+ contextRef.clip(IntRect(1, 1, 9, 9)); |
+ context.save(); |
+ context.clip(IntRect(0, 0, 7, 7)); |
+ context.translate(1, 1); |
+ context.clip(IntRect(0, 0, 7, 7)); |
+ contextRef.save(); |
+ contextRef.clip(IntRect(0, 0, 7, 7)); |
+ contextRef.translate(1, 1); |
+ contextRef.clip(IntRect(0, 0, 7, 7)); |
+ EXPECT_TRUE(equal(canvasRef.getClipStack(), canvas.getClipStack())); |
+ |
+ RoundedRect roundedClipRect(IntRect(20, 20, 70, 70), RoundedRect::Radii(IntSize(2, 3), IntSize(2, 3), IntSize(2, 3), IntSize(2, 3))); |
+ context.beginLayer(1, CompositeSourceOver); |
+ context.scale(0.1, 0.1); |
+ context.clipRoundedRect(roundedClipRect); |
+ context.clipOut(IntRect(40, 40, 10, 10)); |
+ context.endLayer(); |
+ contextRef.scale(0.1, 0.1); |
+ contextRef.clipRoundedRect(roundedClipRect); |
+ contextRef.clipOut(IntRect(40, 40, 10, 10)); |
+ |
+ // GraphicsContext::endLayer() must preserve clip state. |
+ EXPECT_TRUE(equal(canvasRef.getClipStack(), canvas.getClipStack())); |
+ context.restore(); |
+ contextRef.restore(); |
+} |
+ |
} // namespace |