Diff
Modified: trunk/Source/WebCore/ChangeLog (112979 => 112980)
--- trunk/Source/WebCore/ChangeLog 2012-04-03 03:21:01 UTC (rev 112979)
+++ trunk/Source/WebCore/ChangeLog 2012-04-03 03:31:26 UTC (rev 112980)
@@ -1,3 +1,65 @@
+2012-04-02 Dana Jansens <[email protected]>
+
+ [chromium] Remove SkCanvas::LayerIter use from OpaqueRegionSkia
+ https://bugs.webkit.org/show_bug.cgi?id=82564
+
+ Reviewed by Stephen White.
+
+ Per-tile-painting uses an SkPictureRecord in place of an SkCanvas
+ as the painting target for the GraphicsContext. This class only does
+ a simple recording and does not create layers in the canvas during
+ record, only playback. This is preventing us from correctly tracking
+ opaque regions under per-tile-painting.
+
+ We currently use the SkCanvas LayerIter to look at the layers in the
+ canvas backing the GraphicsContext, and check the SkPaints, clips,
+ and transforms to see how they impact the current draw once it reaches
+ the final device.
+
+ The clips and transforms can be retreived without using the LayerIter
+ through the "getTotal*" methods. A cumulative SkPaint is not available
+ so we store this ourselves.
+
+ PlatformContextSkia becomes aware of when saveLayer() is being called
+ on the underlying canvas, and passes this information to the
+ OpaqueRegionSkia class. Since we no longer watch layers in the canvas,
+ we must explicitly handle image clipping for the opaque tracker, as
+ it is implemented in the PlatformContextSkia, not via constructs in
+ the SkCanvas/SkPaint. We save the opaque area of the image mask for
+ the canvas layer in the stack along with the SkPaint for the layer.
+
+ Unit test: PlatformContextSkiaTest.PreserveOpaqueOnlyMattersForFirstLayer
+
+ * platform/graphics/filters/skia/FEGaussianBlurSkia.cpp:
+ (WebCore::FEGaussianBlur::platformApplySkia):
+ * platform/graphics/filters/skia/FEMorphologySkia.cpp:
+ (WebCore::FEMorphology::platformApplySkia):
+ * platform/graphics/skia/GraphicsContextSkia.cpp:
+ (WebCore::GraphicsContext::beginPlatformTransparencyLayer):
+ (WebCore::GraphicsContext::endPlatformTransparencyLayer):
+ * platform/graphics/skia/OpaqueRegionSkia.cpp:
+ (WebCore::OpaqueRegionSkia::pushCanvasLayer):
+ (WebCore):
+ (WebCore::OpaqueRegionSkia::popCanvasLayer):
+ (WebCore::OpaqueRegionSkia::setImageMask):
+ (WebCore::OpaqueRegionSkia::didDrawRect):
+ (WebCore::OpaqueRegionSkia::didDrawPath):
+ (WebCore::OpaqueRegionSkia::didDrawPoints):
+ (WebCore::OpaqueRegionSkia::didDrawBounded):
+ (WebCore::OpaqueRegionSkia::didDraw):
+ (WebCore::OpaqueRegionSkia::didDrawUnbounded):
+ * platform/graphics/skia/OpaqueRegionSkia.h:
+ (OpaqueRegionSkia):
+ (WebCore::OpaqueRegionSkia::CanvasLayerState::CanvasLayerState):
+ (CanvasLayerState):
+ * platform/graphics/skia/PlatformContextSkia.cpp:
+ (WebCore::PlatformContextSkia::saveLayer):
+ (WebCore):
+ (WebCore::PlatformContextSkia::restoreLayer):
+ (WebCore::PlatformContextSkia::beginLayerClippedToImage):
+ * platform/graphics/skia/PlatformContextSkia.h:
+ (PlatformContextSkia):
+
2012-04-02 Shinya Kawanaka <[email protected]>
Remove TreeScope::isShadowRoot.
Modified: trunk/Source/WebCore/platform/graphics/filters/skia/FEGaussianBlurSkia.cpp (112979 => 112980)
--- trunk/Source/WebCore/platform/graphics/filters/skia/FEGaussianBlurSkia.cpp 2012-04-03 03:21:01 UTC (rev 112979)
+++ trunk/Source/WebCore/platform/graphics/filters/skia/FEGaussianBlurSkia.cpp 2012-04-03 03:31:26 UTC (rev 112980)
@@ -51,12 +51,13 @@
SkPaint paint;
GraphicsContext* dstContext = resultImage->context();
- SkCanvas* canvas = dstContext->platformContext()->canvas();
+ PlatformContextSkia* platformContext = dstContext->platformContext();
paint.setImageFilter(new SkBlurImageFilter(stdX, stdY))->unref();
- canvas->saveLayer(0, &paint);
+
+ platformContext->saveLayer(0, &paint);
paint.setColor(0xFFFFFFFF);
dstContext->drawImage(image.get(), ColorSpaceDeviceRGB, drawingRegion.location(), CompositeCopy);
- canvas->restore();
+ platformContext->restoreLayer();
return true;
}
Modified: trunk/Source/WebCore/platform/graphics/filters/skia/FEMorphologySkia.cpp (112979 => 112980)
--- trunk/Source/WebCore/platform/graphics/filters/skia/FEMorphologySkia.cpp 2012-04-03 03:21:01 UTC (rev 112979)
+++ trunk/Source/WebCore/platform/graphics/filters/skia/FEMorphologySkia.cpp 2012-04-03 03:31:26 UTC (rev 112980)
@@ -50,15 +50,15 @@
SkPaint paint;
GraphicsContext* dstContext = resultImage->context();
- SkCanvas* canvas = dstContext->platformContext()->canvas();
+ PlatformContextSkia* platformContext = dstContext->platformContext();
if (m_type == FEMORPHOLOGY_OPERATOR_DILATE)
paint.setImageFilter(new SkDilateImageFilter(radiusX, radiusY))->unref();
else if (m_type == FEMORPHOLOGY_OPERATOR_ERODE)
paint.setImageFilter(new SkErodeImageFilter(radiusX, radiusY))->unref();
- canvas->saveLayer(0, &paint);
+ platformContext->saveLayer(0, &paint);
dstContext->drawImage(image.get(), ColorSpaceDeviceRGB, drawingRegion.location(), CompositeCopy);
- canvas->restore();
+ platformContext->restoreLayer();
return true;
}
Modified: trunk/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp (112979 => 112980)
--- trunk/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp 2012-04-03 03:21:01 UTC (rev 112979)
+++ trunk/Source/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp 2012-04-03 03:31:26 UTC (rev 112980)
@@ -166,23 +166,20 @@
// (the surface of the page) but layers on top may have transparent parts.
// Without explicitly setting the alpha flag, the layer will inherit the
// opaque setting of the base and some things won't work properly.
+ SkCanvas::SaveFlags saveFlags = static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag);
SkPaint layerPaint;
layerPaint.setAlpha(static_cast<unsigned char>(opacity * 255));
layerPaint.setXfermodeMode(platformContext()->getXfermodeMode());
- platformContext()->canvas()->saveLayer(
- 0,
- &layerPaint,
- static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag |
- SkCanvas::kFullColorLayer_SaveFlag));
+ platformContext()->saveLayer(0, &layerPaint, saveFlags);
}
void GraphicsContext::endPlatformTransparencyLayer()
{
if (paintingDisabled())
return;
- platformContext()->canvas()->restore();
+ platformContext()->restoreLayer();
}
bool GraphicsContext::supportsTransparencyLayers()
Modified: trunk/Source/WebCore/platform/graphics/skia/OpaqueRegionSkia.cpp (112979 => 112980)
--- trunk/Source/WebCore/platform/graphics/skia/OpaqueRegionSkia.cpp 2012-04-03 03:21:01 UTC (rev 112979)
+++ trunk/Source/WebCore/platform/graphics/skia/OpaqueRegionSkia.cpp 2012-04-03 03:31:26 UTC (rev 112980)
@@ -147,29 +147,46 @@
return true;
}
-void OpaqueRegionSkia::didDrawRect(PlatformContextSkia* context, const AffineTransform& transform, const SkRect& fillRect, const SkPaint& paint, const SkBitmap* bitmap)
+void OpaqueRegionSkia::pushCanvasLayer(const SkPaint* paint)
{
+ CanvasLayerState state;
+ if (paint)
+ state.paint = *paint;
+ m_canvasLayerStack.append(state);
+}
+
+void OpaqueRegionSkia::popCanvasLayer()
+{
+ m_canvasLayerStack.removeLast();
+}
+
+void OpaqueRegionSkia::setImageMask(const SkRect& imageOpaqueRect)
+{
+ ASSERT(!m_canvasLayerStack.isEmpty());
+ m_canvasLayerStack.last().hasImageMask = true;
+ m_canvasLayerStack.last().imageOpaqueRect = imageOpaqueRect;
+}
+
+void OpaqueRegionSkia::didDrawRect(const PlatformContextSkia* context, const AffineTransform& transform, const SkRect& fillRect, const SkPaint& paint, const SkBitmap* sourceBitmap)
+{
// Any stroking may put alpha in pixels even if the filling part does not.
if (paint.getStyle() != SkPaint::kFill_Style) {
- bool opaque = paintIsOpaque(paint, bitmap);
bool fillsBounds = false;
if (!paint.canComputeFastBounds())
- didDrawUnbounded(paint, opaque);
+ didDrawUnbounded(paint);
else {
SkRect strokeRect;
strokeRect = paint.computeFastBounds(fillRect, &strokeRect);
- didDraw(context, transform, strokeRect, paint, opaque, fillsBounds);
+ didDraw(context, transform, strokeRect, paint, sourceBitmap, fillsBounds, FillOrStroke);
}
}
- bool checkFillOnly = true;
- bool opaque = paintIsOpaque(paint, bitmap, checkFillOnly);
bool fillsBounds = paint.getStyle() != SkPaint::kStroke_Style;
- didDraw(context, transform, fillRect, paint, opaque, fillsBounds);
+ didDraw(context, transform, fillRect, paint, sourceBitmap, fillsBounds, FillOnly);
}
-void OpaqueRegionSkia::didDrawPath(PlatformContextSkia* context, const AffineTransform& transform, 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)) {
@@ -177,18 +194,17 @@
return;
}
- bool opaque = paintIsOpaque(paint);
bool fillsBounds = false;
if (!paint.canComputeFastBounds())
- didDrawUnbounded(paint, opaque);
+ didDrawUnbounded(paint);
else {
rect = paint.computeFastBounds(path.getBounds(), &rect);
- didDraw(context, transform, rect, paint, opaque, fillsBounds);
+ didDraw(context, transform, rect, paint, 0, fillsBounds, FillOrStroke);
}
}
-void OpaqueRegionSkia::didDrawPoints(PlatformContextSkia* context, const AffineTransform& transform, 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;
@@ -206,38 +222,33 @@
rect.fBottom = std::max(rect.fBottom, points[i].fY + 1);
}
- bool opaque = paintIsOpaque(paint);
bool fillsBounds = false;
if (!paint.canComputeFastBounds())
- didDrawUnbounded(paint, opaque);
+ didDrawUnbounded(paint);
else {
rect = paint.computeFastBounds(rect, &rect);
- didDraw(context, transform, rect, paint, opaque, fillsBounds);
+ didDraw(context, transform, rect, paint, 0, fillsBounds, FillOrStroke);
}
}
-void OpaqueRegionSkia::didDrawBounded(PlatformContextSkia* context, const AffineTransform& transform, 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;
if (!paint.canComputeFastBounds())
- didDrawUnbounded(paint, opaque);
+ didDrawUnbounded(paint);
else {
SkRect rect;
rect = paint.computeFastBounds(bounds, &rect);
- didDraw(context, transform, rect, paint, opaque, fillsBounds);
+ didDraw(context, transform, rect, paint, 0, fillsBounds, FillOrStroke);
}
}
-void OpaqueRegionSkia::didDraw(PlatformContextSkia* context, const AffineTransform& transform, 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, const SkBitmap* sourceBitmap, bool fillsBounds, DrawType drawType)
{
SkRect targetRect = rect;
- bool xfersOpaque = xfermodeIsOpaque(paint, drawsOpaque);
- bool preservesOpaque = xfermodePreservesOpaque(paint, drawsOpaque);
-
// Apply the transform to device coordinate space.
SkMatrix canvasTransform = context->canvas()->getTotalMatrix();
if (!canvasTransform.mapRect(&targetRect))
@@ -247,30 +258,39 @@
if (context->canvas()->getClipType() != SkCanvas::kRect_ClipType)
fillsBounds = false;
else {
- SkIRect deviceClip;
- context->canvas()->getClipDeviceBounds(&deviceClip);
+ SkIRect deviceClip = context->canvas()->getTotalClip().getBounds();
if (!targetRect.intersect(SkIntToScalar(deviceClip.fLeft), SkIntToScalar(deviceClip.fTop), SkIntToScalar(deviceClip.fRight), SkIntToScalar(deviceClip.fBottom)))
return;
}
- // Apply any layers that we are drawing into.
- for (SkCanvas::LayerIter it(context->canvas(), false); !it.done(); it.next()) {
- // Apply the layer's clip (which is in device space)
- const SkRegion& deviceLayerClip = it.clip();
- if (deviceLayerClip.isEmpty() || !deviceLayerClip.isRect())
+ bool checkFillOnly = drawType == FillOnly;
+ bool lastLayerDrawsOpaque = paintIsOpaque(paint, sourceBitmap, checkFillOnly);
+
+ bool xfersOpaque = xfermodeIsOpaque(paint, lastLayerDrawsOpaque);
+
+ // Apply the SkCanvas layers we will be drawing through.
+ for (size_t i = m_canvasLayerStack.size(); i > 0; --i) {
+ const CanvasLayerState& canvasLayer = m_canvasLayerStack[i-1];
+
+ // FIXME: We could still track the opaque part but it's always empty right now anyways.
+ if (canvasLayer.hasImageMask && !canvasLayer.imageOpaqueRect.contains(targetRect))
fillsBounds = false;
- else {
- SkIRect clipBounds = it.clip().getBounds();
- if (!targetRect.intersect(SkIntToScalar(clipBounds.fLeft), SkIntToScalar(clipBounds.fTop), SkIntToScalar(clipBounds.fRight), SkIntToScalar(clipBounds.fBottom)))
- return;
- }
- // Make sure the paint stays opaque through the layer.
- bool drawsOpaque = paintIsOpaque(it.paint());
- xfersOpaque = xfersOpaque && xfermodeIsOpaque(it.paint(), drawsOpaque);
- preservesOpaque = preservesOpaque && xfermodePreservesOpaque(it.paint(), drawsOpaque);
+ bool checkFillOnly = drawType == FillOnly;
+ lastLayerDrawsOpaque = paintIsOpaque(canvasLayer.paint, 0, checkFillOnly);
+ // If any layer doesn't paint opaque, then the result will not be opaque.
+ xfersOpaque &= xfermodeIsOpaque(canvasLayer.paint, lastLayerDrawsOpaque);
}
+ // Preserving opaque only matters for the bottom-most layer. Its contents are either opaque or not, and if not
+ // then we care if it preserves the opaqueness of the target device when it is drawn into the device.
+ bool preservesOpaque;
+ if (m_canvasLayerStack.isEmpty())
+ preservesOpaque = xfermodePreservesOpaque(paint, lastLayerDrawsOpaque);
+ else
+ preservesOpaque = xfermodePreservesOpaque(m_canvasLayerStack[0].paint, lastLayerDrawsOpaque);
+
+
// Apply the transform to the tracking space.
SkMatrix canvasToTargetTransform = transform;
if (!canvasToTargetTransform.mapRect(&targetRect))
@@ -282,9 +302,22 @@
markRectAsNonOpaque(targetRect);
}
-void OpaqueRegionSkia::didDrawUnbounded(const SkPaint& paint, bool drawsOpaque)
+void OpaqueRegionSkia::didDrawUnbounded(const SkPaint& paint)
{
- if (!xfermodePreservesOpaque(paint, drawsOpaque)) {
+ // Preserving opaque only matters for the bottom-most layer. Its contents are either opaque or not, and if not
+ // then we care if it preserves the opaqueness of the target device when it is drawn into the device.
+ bool preservesOpaque;
+
+ bool checkFillOnly = false;
+ if (m_canvasLayerStack.isEmpty()) {
+ bool lastLayerDrawsOpaque = paintIsOpaque(paint, 0, checkFillOnly);
+ preservesOpaque = xfermodePreservesOpaque(paint, lastLayerDrawsOpaque);
+ } else {
+ bool lastLayerDrawsOpaque = paintIsOpaque(m_canvasLayerStack[0].paint, 0, checkFillOnly);
+ preservesOpaque = xfermodePreservesOpaque(m_canvasLayerStack[0].paint, lastLayerDrawsOpaque);
+ }
+
+ if (!preservesOpaque) {
// We don't know what was drawn on so just destroy the known opaque area.
m_opaqueRect = SkRect::MakeEmpty();
}
Modified: trunk/Source/WebCore/platform/graphics/skia/OpaqueRegionSkia.h (112979 => 112980)
--- trunk/Source/WebCore/platform/graphics/skia/OpaqueRegionSkia.h 2012-04-03 03:21:01 UTC (rev 112979)
+++ trunk/Source/WebCore/platform/graphics/skia/OpaqueRegionSkia.h 2012-04-03 03:31:26 UTC (rev 112980)
@@ -53,20 +53,41 @@
// The resulting opaque region as a single rect.
IntRect asRect() const;
- // FIXME: make all the PlatformContextSkia* into a const pointer when Skia fixes LayerIter's SkCanvas*.
+ void pushCanvasLayer(const SkPaint*);
+ void popCanvasLayer();
- void didDrawRect(PlatformContextSkia*, const AffineTransform&, const SkRect&, const SkPaint&, const SkBitmap*);
- void didDrawPath(PlatformContextSkia*, const AffineTransform&, const SkPath&, const SkPaint&);
- void didDrawPoints(PlatformContextSkia*, const AffineTransform&, SkCanvas::PointMode, int numPoints, const SkPoint[], const SkPaint&);
- void didDrawBounded(PlatformContextSkia*, const AffineTransform&, const SkRect&, const SkPaint&);
+ void setImageMask(const SkRect& imageOpaqueRect);
+ void didDrawRect(const PlatformContextSkia*, const AffineTransform&, const SkRect&, const SkPaint&, const SkBitmap* sourceBitmap);
+ 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(PlatformContextSkia*, const AffineTransform&, const SkRect&, const SkPaint&, bool drawsOpaque, bool fillsBounds);
- void didDrawUnbounded(const SkPaint&, bool drawsOpaque);
+ enum DrawType {
+ FillOnly,
+ FillOrStroke
+ };
+
+ void didDraw(const PlatformContextSkia*, const AffineTransform&, const SkRect&, const SkPaint&, const SkBitmap* sourceBitmap, bool fillsBounds, DrawType);
+ void didDrawUnbounded(const SkPaint&);
void markRectAsOpaque(const SkRect&);
void markRectAsNonOpaque(const SkRect&);
SkRect m_opaqueRect;
+
+ struct CanvasLayerState {
+ CanvasLayerState() : hasImageMask(false) { }
+
+ SkPaint paint;
+
+ // An image mask is being applied to the layer.
+ bool hasImageMask;
+ // The opaque area in the image mask.
+ SkRect imageOpaqueRect;
+ };
+
+ Vector<CanvasLayerState, 3> m_canvasLayerStack;
};
}
Modified: trunk/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp (112979 => 112980)
--- trunk/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp 2012-04-03 03:21:01 UTC (rev 112979)
+++ trunk/Source/WebCore/platform/graphics/skia/PlatformContextSkia.cpp 2012-04-03 03:31:26 UTC (rev 112980)
@@ -226,28 +226,62 @@
canvas()->save();
}
+void PlatformContextSkia::saveLayer(const SkRect* bounds, const SkPaint* paint)
+{
+ m_canvas->saveLayer(bounds, paint);
+ if (bounds)
+ m_canvas->clipRect(*bounds);
+ if (m_trackOpaqueRegion)
+ m_opaqueRegion.pushCanvasLayer(paint);
+}
+
+void PlatformContextSkia::saveLayer(const SkRect* bounds, const SkPaint* paint, SkCanvas::SaveFlags saveFlags)
+{
+ m_canvas->saveLayer(bounds, paint, saveFlags);
+ if (bounds)
+ m_canvas->clipRect(*bounds);
+ if (m_trackOpaqueRegion)
+ m_opaqueRegion.pushCanvasLayer(paint);
+}
+
+void PlatformContextSkia::restoreLayer()
+{
+ m_canvas->restore();
+ if (m_trackOpaqueRegion)
+ m_opaqueRegion.popCanvasLayer();
+}
+
void PlatformContextSkia::beginLayerClippedToImage(const FloatRect& rect,
const ImageBuffer* imageBuffer)
{
+ SkRect bounds = { SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()),
+ SkFloatToScalar(rect.maxX()), SkFloatToScalar(rect.maxY()) };
+
+ if (imageBuffer->internalSize().isEmpty()) {
+ m_canvas->clipRect(bounds);
+ return;
+ }
+
// Skia doesn't support clipping to an image, so we create a layer. The next
// time restore is invoked the layer and |imageBuffer| are combined to
// create the resulting image.
- SkRect bounds = { SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()),
- SkFloatToScalar(rect.maxX()), SkFloatToScalar(rect.maxY()) };
+
m_state->m_clip = bounds;
// Get the absolute coordinates of the stored clipping rectangle to make it
// independent of any transform changes.
canvas()->getTotalMatrix().mapRect(&m_state->m_clip);
- canvas()->clipRect(bounds);
+ SkCanvas::SaveFlags saveFlags = static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag);
+ saveLayer(&bounds, 0, saveFlags);
- if (imageBuffer->internalSize().isEmpty())
- return;
+ const SkBitmap* bitmap = imageBuffer->context()->platformContext()->bitmap();
- canvas()->saveLayerAlpha(&bounds, 255,
- static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag));
+ if (m_trackOpaqueRegion) {
+ SkRect opaqueRect = bitmap->isOpaque() ? m_state->m_clip : SkRect::MakeEmpty();
+ m_opaqueRegion.setImageMask(opaqueRect);
+ }
+
// Copy off the image as |imageBuffer| may be deleted before restore is invoked.
- const SkBitmap* bitmap = imageBuffer->context()->platformContext()->bitmap();
if (!bitmap->pixelRef()) {
// The bitmap owns it's pixels. This happens when we've allocated the
// pixels in some way and assigned them directly to the bitmap (as
Modified: trunk/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h (112979 => 112980)
--- trunk/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h 2012-04-03 03:21:01 UTC (rev 112979)
+++ trunk/Source/WebCore/platform/graphics/skia/PlatformContextSkia.h 2012-04-03 03:31:26 UTC (rev 112980)
@@ -93,6 +93,10 @@
void save();
void restore();
+ void saveLayer(const SkRect* bounds, const SkPaint*);
+ void saveLayer(const SkRect* bounds, const SkPaint*, SkCanvas::SaveFlags);
+ void restoreLayer();
+
// Begins a layer that is clipped to the image |imageBuffer| at the location
// |rect|. This layer is implicitly restored when the next restore is
// invoked.
Modified: trunk/Source/WebKit/chromium/ChangeLog (112979 => 112980)
--- trunk/Source/WebKit/chromium/ChangeLog 2012-04-03 03:21:01 UTC (rev 112979)
+++ trunk/Source/WebKit/chromium/ChangeLog 2012-04-03 03:31:26 UTC (rev 112980)
@@ -1,3 +1,14 @@
+2012-04-02 Dana Jansens <[email protected]>
+
+ [chromium] Remove SkCanvas::LayerIter use from OpaqueRegionSkia
+ https://bugs.webkit.org/show_bug.cgi?id=82564
+
+ Reviewed by Stephen White.
+
+ * tests/PlatformContextSkiaTest.cpp:
+ (WebCore):
+ (WebCore::TEST):
+
2012-04-02 Mark Pilgrim <[email protected]>
Call decrementStatsCounter directly
Modified: trunk/Source/WebKit/chromium/tests/PlatformContextSkiaTest.cpp (112979 => 112980)
--- trunk/Source/WebKit/chromium/tests/PlatformContextSkiaTest.cpp 2012-04-03 03:21:01 UTC (rev 112979)
+++ trunk/Source/WebKit/chromium/tests/PlatformContextSkiaTest.cpp 2012-04-03 03:31:26 UTC (rev 112980)
@@ -53,6 +53,17 @@
} \
}
+#define EXPECT_PIXELS_MATCH_EXACT(bitmap, opaqueRect) \
+{ \
+ SkAutoLockPixels locker(bitmap); \
+ for (int y = 0; y < bitmap.height(); ++y) \
+ for (int x = 0; x < bitmap.width(); ++x) { \
+ int alpha = *bitmap.getAddr32(x, y) >> 24; \
+ bool opaque = opaqueRect.contains(x, y); \
+ EXPECT_EQ(opaque, alpha == 255); \
+ } \
+}
+
TEST(PlatformContextSkiaTest, trackOpaqueTest)
{
SkBitmap bitmap;
@@ -681,4 +692,86 @@
EXPECT_EQ_RECT(IntRect(), platformContext.opaqueRegion().asRect());
}
+TEST(PlatformContextSkiaTest, PreserveOpaqueOnlyMattersForFirstLayer)
+{
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, 400, 400);
+ bitmap.allocPixels();
+ bitmap.eraseColor(0);
+ SkCanvas canvas(bitmap);
+
+ PlatformContextSkia platformContext(&canvas);
+ platformContext.setTrackOpaqueRegion(true);
+ GraphicsContext context(&platformContext);
+
+ Color opaque(1.0f, 0.0f, 0.0f, 1.0f);
+ Color alpha(0.0f, 0.0f, 0.0f, 0.0f);
+
+ Path path;
+ context.setShouldAntialias(false);
+ context.setMiterLimit(1);
+ context.setStrokeThickness(5);
+ context.setLineCap(SquareCap);
+ context.setStrokeStyle(SolidStroke);
+
+ // Make skia unable to compute fast bounds for our paths.
+ Vector<float> dashArray;
+ dashArray.append(1);
+ dashArray.append(0);
+ context.setLineDash(dashArray, 0);
+
+ // Make the device opaque in 10,10 40x40.
+ context.fillRect(FloatRect(10, 10, 40, 40), opaque, ColorSpaceDeviceRGB, CompositeSourceOver);
+ EXPECT_EQ_RECT(IntRect(10, 10, 40, 40), platformContext.opaqueRegion().asRect());
+ EXPECT_PIXELS_MATCH_EXACT(bitmap, platformContext.opaqueRegion().asRect());
+
+ // Begin a layer that preserves opaque.
+ context.setCompositeOperation(CompositeSourceOver);
+ context.beginTransparencyLayer(0.5);
+
+ // Begin a layer that does not preserve opaque.
+ context.setCompositeOperation(CompositeSourceOut);
+ context.beginTransparencyLayer(0.5);
+
+ // This should not destroy the device opaqueness.
+ context.fillRect(FloatRect(10, 10, 40, 40), opaque, ColorSpaceDeviceRGB, CompositeSourceOver);
+
+ // This should not destroy the device opaqueness either.
+ context.setFillColor(opaque, ColorSpaceDeviceRGB);
+ path.moveTo(FloatPoint(10, 10));
+ path.addLineTo(FloatPoint(40, 40));
+ context.strokePath(path);
+
+ context.endTransparencyLayer();
+ context.endTransparencyLayer();
+ EXPECT_EQ_RECT(IntRect(10, 10, 40, 40), platformContext.opaqueRegion().asRect());
+ EXPECT_PIXELS_MATCH_EXACT(bitmap, platformContext.opaqueRegion().asRect());
+
+ // Now begin a layer that does not preserve opaque and draw through it to the device.
+ context.setCompositeOperation(CompositeSourceOut);
+ context.beginTransparencyLayer(0.5);
+
+ // This should destroy the device opaqueness.
+ context.fillRect(FloatRect(10, 10, 40, 40), opaque, ColorSpaceDeviceRGB, CompositeSourceOver);
+
+ context.endTransparencyLayer();
+ EXPECT_EQ_RECT(IntRect(), platformContext.opaqueRegion().asRect());
+ EXPECT_PIXELS_MATCH_EXACT(bitmap, platformContext.opaqueRegion().asRect());
+
+ // Now we draw with a path for which it cannot compute fast bounds. This should destroy the entire opaque region.
+
+ context.setCompositeOperation(CompositeSourceOut);
+ context.beginTransparencyLayer(0.5);
+
+ // This should nuke the device opaqueness.
+ context.setFillColor(opaque, ColorSpaceDeviceRGB);
+ path.moveTo(FloatPoint(10, 10));
+ path.addLineTo(FloatPoint(40, 40));
+ context.strokePath(path);
+
+ context.endTransparencyLayer();
+ EXPECT_EQ_RECT(IntRect(), platformContext.opaqueRegion().asRect());
+ EXPECT_PIXELS_MATCH_EXACT(bitmap, platformContext.opaqueRegion().asRect());
+}
+
} // namespace