Title: [112980] trunk/Source
Revision
112980
Author
[email protected]
Date
2012-04-02 20:31:26 -0700 (Mon, 02 Apr 2012)

Log Message

[chromium] Remove SkCanvas::LayerIter use from OpaqueRegionSkia
https://bugs.webkit.org/show_bug.cgi?id=82564

Patch by Dana Jansens <[email protected]> on 2012-04-02
Reviewed by Stephen White.

Source/WebCore:

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):

Source/WebKit/chromium:

* tests/PlatformContextSkiaTest.cpp:
(WebCore):
(WebCore::TEST):

Modified Paths

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
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to