https://bugs.webkit.org/show_bug.cgi?id=78073
Patch by Dana Jansens <danakj@chromium.org> on 2012-02-08
Reviewed by Stephen White.
Source/WebCore:
Tests: compositing/culling/scrolled-within-boxshadow.html
compositing/culling/translated-boxshadow.html
Unit tests: PlatformContextSkiaTest.cpp
When painting a box shadow, a filter is applied to the skia canvas, that can make
pixels painted with an opaque color end up non-opaque. So consider image/mask/color
filters when deciding if a paint is opaque.
Also when painting the background of an element with a box shadow, the background is
painted with a transform on the skia canvas based on the size of the box shadow. This
transform needs to be considered when tracking an opaque paint.
However, when a layer's contentRect position is non-zero, we translate the GraphicsContext
to put the contentRect at 0,0 in the skia canvas. For tracking opaque regions in the resulting
layer, we need to unto this translation. Scaling can also occur which we must undo. So we pass
the transform in to PlatformContextSkia to go from the SkCanvas back to the layer's content
coordinate space. Opaque paints can then be tracked in the layer's content space rather than
in the skia canvas space.
* platform/graphics/chromium/BitmapCanvasLayerTextureUpdater.cpp:
(WebCore::BitmapCanvasLayerTextureUpdater::prepareToUpdate):
* platform/graphics/chromium/CanvasLayerTextureUpdater.cpp:
(WebCore::CanvasLayerTextureUpdater::paintContents):
* platform/graphics/chromium/CanvasLayerTextureUpdater.h:
(WebCore):
(CanvasLayerTextureUpdater):
* platform/graphics/chromium/SkPictureCanvasLayerTextureUpdater.cpp:
(WebCore::SkPictureCanvasLayerTextureUpdater::prepareToUpdate):
* platform/graphics/skia/OpaqueRegionSkia.cpp:
(WebCore::paintIsOpaque):
(WebCore::OpaqueRegionSkia::didDrawRect):
(WebCore::OpaqueRegionSkia::didDrawPath):
(WebCore::OpaqueRegionSkia::didDrawPoints):
(WebCore::OpaqueRegionSkia::didDrawBounded):
(WebCore::OpaqueRegionSkia::didDraw):
(WebCore::OpaqueRegionSkia::markRectAsOpaque):
(WebCore::OpaqueRegionSkia::markRectAsNonOpaque):
* platform/graphics/skia/OpaqueRegionSkia.h:
(WebCore):
(OpaqueRegionSkia):
* platform/graphics/skia/PlatformContextSkia.cpp:
(WebCore::PlatformContextSkia::didDrawRect):
(WebCore::PlatformContextSkia::didDrawPath):
(WebCore::PlatformContextSkia::didDrawPoints):
(WebCore::PlatformContextSkia::didDrawBounded):
* platform/graphics/skia/PlatformContextSkia.h:
(PlatformContextSkia):
(WebCore::PlatformContextSkia::setOpaqueRegionTransform):
Source/WebKit/chromium:
* tests/PlatformContextSkiaTest.cpp:
(WebCore::TEST):
(WebCore):
LayoutTests:
* compositing/culling/scrolled-within-boxshadow-expected.png: Added.
* compositing/culling/scrolled-within-boxshadow-expected.txt: Added.
* compositing/culling/scrolled-within-boxshadow.html: Added.
* compositing/culling/translated-boxshadow-expected.png: Added.
* compositing/culling/translated-boxshadow-expected.txt: Added.
* compositing/culling/translated-boxshadow.html: Added.
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@107143
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2012-02-08 Dana Jansens <danakj@chromium.org>
+
+ [Chromium] Fix opaque tracking for box shadows and non-composited child elements
+ https://bugs.webkit.org/show_bug.cgi?id=78073
+
+ Reviewed by Stephen White.
+
+ * compositing/culling/scrolled-within-boxshadow-expected.png: Added.
+ * compositing/culling/scrolled-within-boxshadow-expected.txt: Added.
+ * compositing/culling/scrolled-within-boxshadow.html: Added.
+ * compositing/culling/translated-boxshadow-expected.png: Added.
+ * compositing/culling/translated-boxshadow-expected.txt: Added.
+ * compositing/culling/translated-boxshadow.html: Added.
+
2012-02-08 Julien Chaffraix <jchaffraix@webkit.org>
Unreviewed gardening.
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+.comp {
+ -webkit-transform: translateZ(0px);
+}
+body {
+ margin:0;
+ padding:0;
+}
+.shadow {
+ position:absolute;
+ left:20px; right:20px;
+ width:500px;
+ height:500px;
+ top:0px; bottom:20px;
+ z-index:120;
+ margin-top:20px;
+ border: 1px solid transparent;
+ -webkit-box-shadow: 0 0 6px #090;
+ background-color: #090;
+}
+#scroll {
+ overflow-y: hidden; /* scrollable but no scrollbars visible. */
+ width:500px;
+ height: 500px;
+}
+.scrollContent {
+ width:100%;
+ height: 1000px; /* make the container scrollable */
+ background-color: #0d0;
+}
+</style>
+<script type="text/javascript">
+ if (window.layoutTestController) {
+ layoutTestController.dumpAsText(true);
+ layoutTestController.waitUntilDone();
+ }
+
+ window.onload = function() { setTimeout(function() {
+ document.getElementById('scroll').scrollTop += 300;
+ if (window.layoutTestController) {
+ layoutTestController.notifyDone();
+ }
+ }, 0); };
+</script>
+</head>
+
+<body>
+<!-- If culled incorrectly, the top/left edges outside of the shadowed box end up being culled instead of painted/drawn properly. -->
+<div class="comp shadow">
+ <div id="scroll">
+ <div class="scrollContent">
+ </div>
+ </div>
+</div>
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+.comp {
+ -webkit-transform: translateZ(0px);
+}
+body {
+ margin:0;
+ padding:0;
+}
+.shadow {
+ position:absolute;
+ left:20px; right:20px;
+ width:500px;
+ height:500px;
+ top:0px; bottom:20px;
+ z-index:120;
+ margin-top:20px;
+ border: 1px solid transparent;
+ -webkit-box-shadow: 0 0 6px #090;
+ background-color: #090;
+}
+</style>
+<script type="text/javascript">
+ if (window.layoutTestController) {
+ layoutTestController.dumpAsText(true);
+ }
+</script>
+</head>
+
+<body>
+<!-- If culled incorrectly, the top/left edges outside of the shadowed box end up being culled instead of painted/drawn properly. -->
+<div class="comp shadow"></div>
+</body>
+</html>
+2012-02-08 Dana Jansens <danakj@chromium.org>
+
+ [Chromium] Fix opaque tracking for box shadows and non-composited child elements
+ https://bugs.webkit.org/show_bug.cgi?id=78073
+
+ Reviewed by Stephen White.
+
+ Tests: compositing/culling/scrolled-within-boxshadow.html
+ compositing/culling/translated-boxshadow.html
+
+ Unit tests: PlatformContextSkiaTest.cpp
+
+ When painting a box shadow, a filter is applied to the skia canvas, that can make
+ pixels painted with an opaque color end up non-opaque. So consider image/mask/color
+ filters when deciding if a paint is opaque.
+
+ Also when painting the background of an element with a box shadow, the background is
+ painted with a transform on the skia canvas based on the size of the box shadow. This
+ transform needs to be considered when tracking an opaque paint.
+
+ However, when a layer's contentRect position is non-zero, we translate the GraphicsContext
+ to put the contentRect at 0,0 in the skia canvas. For tracking opaque regions in the resulting
+ layer, we need to unto this translation. Scaling can also occur which we must undo. So we pass
+ the transform in to PlatformContextSkia to go from the SkCanvas back to the layer's content
+ coordinate space. Opaque paints can then be tracked in the layer's content space rather than
+ in the skia canvas space.
+
+ * platform/graphics/chromium/BitmapCanvasLayerTextureUpdater.cpp:
+ (WebCore::BitmapCanvasLayerTextureUpdater::prepareToUpdate):
+ * platform/graphics/chromium/CanvasLayerTextureUpdater.cpp:
+ (WebCore::CanvasLayerTextureUpdater::paintContents):
+ * platform/graphics/chromium/CanvasLayerTextureUpdater.h:
+ (WebCore):
+ (CanvasLayerTextureUpdater):
+ * platform/graphics/chromium/SkPictureCanvasLayerTextureUpdater.cpp:
+ (WebCore::SkPictureCanvasLayerTextureUpdater::prepareToUpdate):
+ * platform/graphics/skia/OpaqueRegionSkia.cpp:
+ (WebCore::paintIsOpaque):
+ (WebCore::OpaqueRegionSkia::didDrawRect):
+ (WebCore::OpaqueRegionSkia::didDrawPath):
+ (WebCore::OpaqueRegionSkia::didDrawPoints):
+ (WebCore::OpaqueRegionSkia::didDrawBounded):
+ (WebCore::OpaqueRegionSkia::didDraw):
+ (WebCore::OpaqueRegionSkia::markRectAsOpaque):
+ (WebCore::OpaqueRegionSkia::markRectAsNonOpaque):
+ * platform/graphics/skia/OpaqueRegionSkia.h:
+ (WebCore):
+ (OpaqueRegionSkia):
+ * platform/graphics/skia/PlatformContextSkia.cpp:
+ (WebCore::PlatformContextSkia::didDrawRect):
+ (WebCore::PlatformContextSkia::didDrawPath):
+ (WebCore::PlatformContextSkia::didDrawPoints):
+ (WebCore::PlatformContextSkia::didDrawBounded):
+ * platform/graphics/skia/PlatformContextSkia.h:
+ (PlatformContextSkia):
+ (WebCore::PlatformContextSkia::setOpaqueRegionTransform):
+
2012-02-08 Kentaro Hara <haraken@chromium.org>
Remove [CustomHeader] from CanvasPixelArray and rename [CustomHeader] to [JSCustomHeader]
borderTexels ? PlatformCanvas::Painter::GrayscaleText : PlatformCanvas::Painter::SubpixelText;
PlatformCanvas::Painter canvasPainter(&m_canvas, textOption);
canvasPainter.skiaContext()->setTrackOpaqueRegion(!layerIsOpaque);
- paintContents(*canvasPainter.context(), contentRect, contentsScale);
+ paintContents(*canvasPainter.context(), *canvasPainter.skiaContext(), contentRect, contentsScale);
if (!layerIsOpaque)
*resultingOpaqueRect = canvasPainter.skiaContext()->opaqueRegion().asRect();
#include "GraphicsContext.h"
#include "LayerPainterChromium.h"
+#include "PlatformContextSkia.h"
#include "TraceEvent.h"
namespace WebCore {
{
}
-void CanvasLayerTextureUpdater::paintContents(GraphicsContext& context, const IntRect& contentRect, float contentsScale)
+void CanvasLayerTextureUpdater::paintContents(GraphicsContext& context, PlatformContextSkia& platformContext, const IntRect& contentRect, float contentsScale)
{
context.translate(-contentRect.x(), -contentRect.y());
{
scaledContentRect = enclosingIntRect(rect);
}
+ // Transform tracked opaque paints back to our layer's content space.
+ ASSERT(context.getCTM().isInvertible());
+ platformContext.setOpaqueRegionTransform(context.getCTM().inverse());
+
m_painter->paint(context, scaledContentRect);
if (contentsScale != 1.0)
class GraphicsContext3D;
class LayerPainterChromium;
+class PlatformContextSkia;
// Base class for BitmapCanvasLayerTextureUpdater and
// SkPictureCanvasLayerTextureUpdater that reduces code duplication between
protected:
explicit CanvasLayerTextureUpdater(PassOwnPtr<LayerPainterChromium>);
- void paintContents(GraphicsContext&, const IntRect& contentRect, float contentsScale);
+ void paintContents(GraphicsContext&, PlatformContextSkia&, const IntRect& contentRect, float contentsScale);
const IntRect& contentRect() const { return m_contentRect; }
private:
platformContext.setDeferred(true);
platformContext.setTrackOpaqueRegion(!m_layerIsOpaque);
GraphicsContext graphicsContext(&platformContext);
- paintContents(graphicsContext, contentRect, contentsScale);
+ paintContents(graphicsContext, platformContext, contentRect, contentsScale);
m_picture.endRecording();
if (!m_layerIsOpaque)
#include "PlatformContextSkia.h"
#include "SkCanvas.h"
+#include "SkColorFilter.h"
#include "SkShader.h"
namespace WebCore {
return false;
if (bitmap && !bitmap->isOpaque())
return false;
+ if (paint.getLooper())
+ return false;
+ if (paint.getImageFilter())
+ return false;
+ if (paint.getMaskFilter())
+ return false;
+ SkColorFilter* colorFilter = paint.getColorFilter();
+ if (colorFilter && !(colorFilter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag))
+ return false;
return true;
}
-void OpaqueRegionSkia::didDrawRect(const PlatformContextSkia* context, const SkRect& fillRect, const SkPaint& paint, const SkBitmap* bitmap)
+void OpaqueRegionSkia::didDrawRect(const PlatformContextSkia* context, const AffineTransform& transform, const SkRect& fillRect, const SkPaint& paint, const SkBitmap* bitmap)
{
// Any stroking may put alpha in pixels even if the filling part does not.
if (paint.getStyle() != SkPaint::kFill_Style) {
else {
SkRect strokeRect;
strokeRect = paint.computeFastBounds(fillRect, &strokeRect);
- didDraw(context, strokeRect, paint, opaque, fillsBounds);
+ didDraw(context, transform, strokeRect, paint, opaque, fillsBounds);
}
}
bool checkFillOnly = true;
bool opaque = paintIsOpaque(paint, bitmap, checkFillOnly);
bool fillsBounds = paint.getStyle() != SkPaint::kStroke_Style;
- didDraw(context, fillRect, paint, opaque, fillsBounds);
+ didDraw(context, transform, fillRect, paint, opaque, fillsBounds);
}
-void OpaqueRegionSkia::didDrawPath(const PlatformContextSkia* context, const SkPath& path, const SkPaint& paint)
+void OpaqueRegionSkia::didDrawPath(const PlatformContextSkia* context, const AffineTransform& transform, const SkPath& path, const SkPaint& paint)
{
SkRect rect;
if (path.isRect(&rect)) {
- didDrawRect(context, rect, paint, 0);
+ didDrawRect(context, transform, rect, paint, 0);
return;
}
didDrawUnbounded(paint, opaque);
else {
rect = paint.computeFastBounds(path.getBounds(), &rect);
- didDraw(context, rect, paint, opaque, fillsBounds);
+ didDraw(context, transform, rect, paint, opaque, fillsBounds);
}
}
-void OpaqueRegionSkia::didDrawPoints(const PlatformContextSkia* context, SkCanvas::PointMode mode, int numPoints, const SkPoint points[], const SkPaint& paint)
+void OpaqueRegionSkia::didDrawPoints(const PlatformContextSkia* context, const AffineTransform& transform, SkCanvas::PointMode mode, int numPoints, const SkPoint points[], const SkPaint& paint)
{
if (!numPoints)
return;
didDrawUnbounded(paint, opaque);
else {
rect = paint.computeFastBounds(rect, &rect);
- didDraw(context, rect, paint, opaque, fillsBounds);
+ didDraw(context, transform, rect, paint, opaque, fillsBounds);
}
}
-void OpaqueRegionSkia::didDrawBounded(const PlatformContextSkia* context, const SkRect& bounds, const SkPaint& paint)
+void OpaqueRegionSkia::didDrawBounded(const PlatformContextSkia* context, const AffineTransform& transform, const SkRect& bounds, const SkPaint& paint)
{
bool opaque = paintIsOpaque(paint);
bool fillsBounds = false;
else {
SkRect rect;
rect = paint.computeFastBounds(bounds, &rect);
- didDraw(context, rect, paint, opaque, fillsBounds);
+ didDraw(context, transform, rect, paint, opaque, fillsBounds);
}
}
-void OpaqueRegionSkia::didDraw(const PlatformContextSkia* context, const SkRect& rect, const SkPaint& paint, bool drawsOpaque, bool fillsBounds)
+void OpaqueRegionSkia::didDraw(const PlatformContextSkia* context, const AffineTransform& transform, const SkRect& rect, const SkPaint& paint, bool drawsOpaque, bool fillsBounds)
{
+ SkRect targetRect = rect;
+
+ // Apply the current clip.
+ if (context->canvas()->getClipType() != SkCanvas::kRect_ClipType)
+ fillsBounds = false;
+ else {
+ SkIRect deviceClip;
+ context->canvas()->getClipDeviceBounds(&deviceClip);
+ if (!targetRect.intersect(SkIntToScalar(deviceClip.fLeft), SkIntToScalar(deviceClip.fTop), SkIntToScalar(deviceClip.fRight), SkIntToScalar(deviceClip.fBottom)))
+ return;
+ }
+ if (!context->clippedToImage().isOpaque())
+ fillsBounds = false;
+
+ // Apply the transforms.
+ SkMatrix canvasTransform = context->canvas()->getTotalMatrix();
+ if (!canvasTransform.mapRect(&targetRect))
+ fillsBounds = false;
+ SkMatrix canvasToTargetTransform = transform;
+ if (!canvasToTargetTransform.mapRect(&targetRect))
+ fillsBounds = false;
+
if (fillsBounds && xfermodeIsOpaque(paint, drawsOpaque))
- markRectAsOpaque(context, rect);
- else if (SkRect::Intersects(rect, m_opaqueRect) && !xfermodePreservesOpaque(paint, drawsOpaque))
- markRectAsNonOpaque(rect);
+ markRectAsOpaque(targetRect);
+ else if (SkRect::Intersects(targetRect, m_opaqueRect) && !xfermodePreservesOpaque(paint, drawsOpaque))
+ markRectAsNonOpaque(targetRect);
}
void OpaqueRegionSkia::didDrawUnbounded(const SkPaint& paint, bool drawsOpaque)
}
}
-void OpaqueRegionSkia::markRectAsOpaque(const PlatformContextSkia* context, const SkRect& paintRect)
+void OpaqueRegionSkia::markRectAsOpaque(const SkRect& rect)
{
// We want to keep track of an opaque region but bound its complexity at a constant size.
// We keep track of the largest rectangle seen by area. If we can add the new rect to this
// rectangle then we do that, as that is the cheapest way to increase the area returned
// without increasing the complexity.
- if (paintRect.isEmpty())
- return;
- if (!context->clippedToImage().isOpaque())
- return;
- if (context->canvas()->getClipType() != SkCanvas::kRect_ClipType)
+ if (rect.isEmpty())
return;
- if (m_opaqueRect.contains(paintRect))
+ if (m_opaqueRect.contains(rect))
return;
-
- // Apply the current clip.
- SkIRect deviceClip;
- context->canvas()->getClipDeviceBounds(&deviceClip);
- SkRect rect = paintRect;
- if (!rect.intersect(SkIntToScalar(deviceClip.fLeft), SkIntToScalar(deviceClip.fTop), SkIntToScalar(deviceClip.fRight), SkIntToScalar(deviceClip.fBottom)))
- return;
-
if (rect.contains(m_opaqueRect)) {
m_opaqueRect = rect;
return;
#include "SkRect.h"
namespace WebCore {
+class AffineTransform;
class PlatformContextSkia;
// This class is an encapsulation of functionality for PlatformContextSkia, and its methods are mirrored
// The resulting opaque region as a single rect.
IntRect asRect() const;
- void didDrawRect(const PlatformContextSkia*, const SkRect&, const SkPaint&, const SkBitmap*);
- void didDrawPath(const PlatformContextSkia*, const SkPath&, const SkPaint&);
- void didDrawPoints(const PlatformContextSkia*, SkCanvas::PointMode, int numPoints, const SkPoint[], const SkPaint&);
- void didDrawBounded(const PlatformContextSkia*, const SkRect&, const SkPaint&);
+ void didDrawRect(const PlatformContextSkia*, const AffineTransform&, const SkRect&, const SkPaint&, const SkBitmap*);
+ void didDrawPath(const PlatformContextSkia*, const AffineTransform&, const SkPath&, const SkPaint&);
+ void didDrawPoints(const PlatformContextSkia*, const AffineTransform&, SkCanvas::PointMode, int numPoints, const SkPoint[], const SkPaint&);
+ void didDrawBounded(const PlatformContextSkia*, const AffineTransform&, const SkRect&, const SkPaint&);
private:
- void didDraw(const PlatformContextSkia*, const SkRect&, const SkPaint&, bool drawsOpaque, bool fillsBounds);
+ void didDraw(const PlatformContextSkia*, const AffineTransform&, const SkRect&, const SkPaint&, bool drawsOpaque, bool fillsBounds);
void didDrawUnbounded(const SkPaint&, bool drawsOpaque);
- void markRectAsOpaque(const PlatformContextSkia*, const SkRect&);
+ void markRectAsOpaque(const SkRect&);
void markRectAsNonOpaque(const SkRect&);
SkRect m_opaqueRect;
#include "PlatformContextSkia.h"
-#include "AffineTransform.h"
#include "Extensions3D.h"
#include "GraphicsContext.h"
#include "GraphicsContext3D.h"
void PlatformContextSkia::didDrawRect(const SkRect& rect, const SkPaint& paint, const SkBitmap* bitmap)
{
if (m_trackOpaqueRegion)
- m_opaqueRegion.didDrawRect(this, rect, paint, bitmap);
+ m_opaqueRegion.didDrawRect(this, m_opaqueRegionTransform, rect, paint, bitmap);
}
void PlatformContextSkia::didDrawPath(const SkPath& path, const SkPaint& paint)
{
if (m_trackOpaqueRegion)
- m_opaqueRegion.didDrawPath(this, path, paint);
+ m_opaqueRegion.didDrawPath(this, m_opaqueRegionTransform, path, paint);
}
void PlatformContextSkia::didDrawPoints(SkCanvas::PointMode mode, int numPoints, const SkPoint points[], const SkPaint& paint)
{
if (m_trackOpaqueRegion)
- m_opaqueRegion.didDrawPoints(this, mode, numPoints, points, paint);
+ m_opaqueRegion.didDrawPoints(this, m_opaqueRegionTransform, mode, numPoints, points, paint);
}
void PlatformContextSkia::didDrawBounded(const SkRect& rect, const SkPaint& paint)
{
if (m_trackOpaqueRegion)
- m_opaqueRegion.didDrawBounded(this, rect, paint);
+ m_opaqueRegion.didDrawBounded(this, m_opaqueRegionTransform, rect, paint);
}
} // namespace WebCore
#ifndef PlatformContextSkia_h
#define PlatformContextSkia_h
+#include "AffineTransform.h"
#include "GraphicsContext.h"
#include "Noncopyable.h"
#include "OpaqueRegionSkia.h"
void setDeferred(bool deferred) { m_deferred = deferred; }
void setTrackOpaqueRegion(bool track) { m_trackOpaqueRegion = track; }
+ // A transform applied to all tracked opaque paints. This is applied at the time the painting is done.
+ void setOpaqueRegionTransform(const AffineTransform& transform) { m_opaqueRegionTransform = transform; }
// This will be an empty region unless tracking is enabled.
const OpaqueRegionSkia& opaqueRegion() const { return m_opaqueRegion; }
// Tracks the region painted opaque via the GraphicsContext.
OpaqueRegionSkia m_opaqueRegion;
bool m_trackOpaqueRegion;
+ AffineTransform m_opaqueRegionTransform;
// Stores image sizes for a hint to compute image resampling modes.
// Values are used in ImageSkia.cpp
+2012-02-08 Dana Jansens <danakj@chromium.org>
+
+ [Chromium] Fix opaque tracking for box shadows and non-composited child elements
+ https://bugs.webkit.org/show_bug.cgi?id=78073
+
+ Reviewed by Stephen White.
+
+ * tests/PlatformContextSkiaTest.cpp:
+ (WebCore::TEST):
+ (WebCore):
+
2012-02-08 Shawn Singh <shawnsingh@chromium.org>
[chromium] Remove incorrect early exit in CCDamageTracker
EXPECT_PIXELS_MATCH(bitmap, platformContext.opaqueRegion().asRect());
}
+TEST(PlatformContextSkiaTest, layerTransformTranslateOpaqueTest)
+{
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, 400, 400);
+ bitmap.allocPixels();
+ bitmap.eraseColor(0);
+ SkCanvas canvas(bitmap);
+ AffineTransform transform;
+ transform.translate(10, 10);
+
+ PlatformContextSkia platformContext(&canvas);
+ platformContext.setTrackOpaqueRegion(true);
+ platformContext.setOpaqueRegionTransform(transform);
+ GraphicsContext context(&platformContext);
+
+ Color opaque(1.0f, 0.0f, 0.0f, 1.0f);
+
+ context.fillRect(FloatRect(10, 10, 90, 90), opaque, ColorSpaceDeviceRGB, CompositeSourceOver);
+ EXPECT_EQ_RECT(IntRect(20, 20, 90, 90), platformContext.opaqueRegion().asRect());
+ EXPECT_PIXELS_MATCH(bitmap, transform.inverse().mapRect(platformContext.opaqueRegion().asRect()));
+
+ context.clearRect(FloatRect(10, 10, 90, 90));
+ EXPECT_EQ_RECT(IntRect(), platformContext.opaqueRegion().asRect());
+
+ context.translate(30, 30);
+
+ context.fillRect(FloatRect(10, 10, 90, 90), opaque, ColorSpaceDeviceRGB, CompositeSourceOver);
+ EXPECT_EQ_RECT(IntRect(50, 50, 90, 90), platformContext.opaqueRegion().asRect());
+ EXPECT_PIXELS_MATCH(bitmap, transform.inverse().mapRect(platformContext.opaqueRegion().asRect()));
+
+ context.clearRect(FloatRect(10, 10, 90, 90));
+ EXPECT_EQ_RECT(IntRect(), platformContext.opaqueRegion().asRect());
+}
+
+TEST(PlatformContextSkiaTest, layerTransformScaleOpaqueTest)
+{
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, 400, 400);
+ bitmap.allocPixels();
+ bitmap.eraseColor(0);
+ SkCanvas canvas(bitmap);
+ AffineTransform transform;
+ transform.scale(2);
+
+ PlatformContextSkia platformContext(&canvas);
+ platformContext.setTrackOpaqueRegion(true);
+ platformContext.setOpaqueRegionTransform(transform);
+ GraphicsContext context(&platformContext);
+
+ Color opaque(1.0f, 0.0f, 0.0f, 1.0f);
+
+ context.fillRect(FloatRect(20, 20, 10, 10), opaque, ColorSpaceDeviceRGB, CompositeSourceOver);
+ EXPECT_EQ_RECT(IntRect(40, 40, 20, 20), platformContext.opaqueRegion().asRect());
+ EXPECT_PIXELS_MATCH(bitmap, transform.inverse().mapRect(platformContext.opaqueRegion().asRect()));
+
+ context.clearRect(FloatRect(20, 20, 10, 10));
+ EXPECT_EQ_RECT(IntRect(), platformContext.opaqueRegion().asRect());
+
+ context.scale(FloatSize(2, 1));
+ context.translate(0, 10);
+
+ context.fillRect(FloatRect(20, 20, 10, 10), opaque, ColorSpaceDeviceRGB, CompositeSourceOver);
+ EXPECT_EQ_RECT(IntRect(80, 60, 40, 20), platformContext.opaqueRegion().asRect());
+ EXPECT_PIXELS_MATCH(bitmap, transform.inverse().mapRect(platformContext.opaqueRegion().asRect()));
+
+ context.clearRect(FloatRect(20, 20, 10, 10));
+ EXPECT_EQ_RECT(IntRect(), platformContext.opaqueRegion().asRect());
+}
+
} // namespace