| OLD | NEW | 
|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "core/paint/SVGClipPainter.h" | 5 #include "core/paint/SVGClipPainter.h" | 
| 6 | 6 | 
| 7 #include "core/dom/ElementTraversal.h" | 7 #include "core/dom/ElementTraversal.h" | 
| 8 #include "core/layout/svg/LayoutSVGResourceClipper.h" | 8 #include "core/layout/svg/LayoutSVGResourceClipper.h" | 
| 9 #include "core/layout/svg/SVGLayoutSupport.h" | 9 #include "core/layout/svg/SVGLayoutSupport.h" | 
| 10 #include "core/layout/svg/SVGResources.h" | 10 #include "core/layout/svg/SVGResources.h" | 
| 11 #include "core/layout/svg/SVGResourcesCache.h" | 11 #include "core/layout/svg/SVGResourcesCache.h" | 
|  | 12 #include "core/paint/ClipPathClipper.h" | 
| 12 #include "core/paint/LayoutObjectDrawingRecorder.h" | 13 #include "core/paint/LayoutObjectDrawingRecorder.h" | 
| 13 #include "core/paint/PaintInfo.h" | 14 #include "core/paint/PaintInfo.h" | 
| 14 #include "core/paint/TransformRecorder.h" | 15 #include "core/paint/TransformRecorder.h" | 
| 15 #include "platform/graphics/paint/ClipPathDisplayItem.h" | 16 #include "platform/graphics/paint/ClipPathDisplayItem.h" | 
|  | 17 #include "platform/graphics/paint/ClipPathRecorder.h" | 
| 16 #include "platform/graphics/paint/CompositingRecorder.h" | 18 #include "platform/graphics/paint/CompositingRecorder.h" | 
| 17 #include "platform/graphics/paint/DrawingDisplayItem.h" | 19 #include "platform/graphics/paint/DrawingDisplayItem.h" | 
| 18 #include "platform/graphics/paint/PaintController.h" | 20 #include "platform/graphics/paint/PaintController.h" | 
| 19 #include "platform/graphics/paint/SkPictureBuilder.h" | 21 #include "platform/graphics/paint/SkPictureBuilder.h" | 
| 20 | 22 | 
| 21 namespace blink { | 23 namespace blink { | 
| 22 | 24 | 
| 23 namespace { | 25 namespace { | 
| 24 | 26 | 
| 25 class SVGClipExpansionCycleHelper { | 27 class SVGClipExpansionCycleHelper { | 
| 26 public: | 28 public: | 
| 27     SVGClipExpansionCycleHelper(LayoutSVGResourceClipper& clip) : m_clip(clip) {
      clip.beginClipExpansion(); } | 29     SVGClipExpansionCycleHelper(LayoutSVGResourceClipper& clip) : m_clip(clip) {
      clip.beginClipExpansion(); } | 
| 28     ~SVGClipExpansionCycleHelper() { m_clip.endClipExpansion(); } | 30     ~SVGClipExpansionCycleHelper() { m_clip.endClipExpansion(); } | 
| 29 private: | 31 private: | 
| 30     LayoutSVGResourceClipper& m_clip; | 32     LayoutSVGResourceClipper& m_clip; | 
| 31 }; | 33 }; | 
| 32 | 34 | 
| 33 } // namespace | 35 } // namespace | 
| 34 | 36 | 
| 35 bool SVGClipPainter::prepareEffect(const LayoutObject& target, const FloatRect& 
     targetBoundingBox, | 37 bool SVGClipPainter::prepareEffect(const LayoutObject& target, const FloatRect& 
     targetBoundingBox, | 
| 36     const FloatRect& paintInvalidationRect, const FloatPoint& layerPositionOffse
     t, GraphicsContext& context, ClipperState& clipperState) | 38     const FloatRect& paintInvalidationRect, const FloatPoint& layerPositionOffse
     t, GraphicsContext& context, ClipperState& clipperState) | 
| 37 { | 39 { | 
| 38     ASSERT(clipperState == ClipperNotApplied); | 40     DCHECK_EQ(clipperState, ClipperState::NotApplied); | 
| 39     ASSERT_WITH_SECURITY_IMPLICATION(!m_clip.needsLayout()); | 41     SECURITY_DCHECK(!m_clip.needsLayout()); | 
| 40 | 42 | 
| 41     m_clip.clearInvalidationMask(); | 43     m_clip.clearInvalidationMask(); | 
| 42 | 44 | 
| 43     if (paintInvalidationRect.isEmpty() || m_clip.hasCycle()) | 45     if (paintInvalidationRect.isEmpty() || m_clip.hasCycle()) | 
| 44         return false; | 46         return false; | 
| 45 | 47 | 
| 46     SVGClipExpansionCycleHelper inClipExpansionChange(m_clip); | 48     SVGClipExpansionCycleHelper inClipExpansionChange(m_clip); | 
| 47 | 49 | 
| 48     AffineTransform animatedLocalTransform = toSVGClipPathElement(m_clip.element
     ())->calculateAnimatedLocalTransform(); | 50     AffineTransform animatedLocalTransform = toSVGClipPathElement(m_clip.element
     ())->calculateAnimatedLocalTransform(); | 
| 49     // When drawing a clip for non-SVG elements, the CTM does not include the zo
     om factor. | 51     // When drawing a clip for non-SVG elements, the CTM does not include the zo
     om factor. | 
| 50     // In this case, we need to apply the zoom scale explicitly - but only for c
     lips with | 52     // In this case, we need to apply the zoom scale explicitly - but only for c
     lips with | 
| 51     // userSpaceOnUse units (the zoom is accounted for objectBoundingBox-resolve
     d lengths). | 53     // userSpaceOnUse units (the zoom is accounted for objectBoundingBox-resolve
     d lengths). | 
| 52     if (!target.isSVG() && m_clip.clipPathUnits() == SVGUnitTypes::kSvgUnitTypeU
     serspaceonuse) { | 54     if (!target.isSVG() && m_clip.clipPathUnits() == SVGUnitTypes::kSvgUnitTypeU
     serspaceonuse) { | 
| 53         ASSERT(m_clip.style()); | 55         DCHECK(m_clip.style()); | 
| 54         animatedLocalTransform.scale(m_clip.style()->effectiveZoom()); | 56         animatedLocalTransform.scale(m_clip.style()->effectiveZoom()); | 
| 55     } | 57     } | 
| 56 | 58 | 
| 57     // First, try to apply the clip as a clipPath. | 59     // First, try to apply the clip as a clipPath. | 
| 58     Path clipPath; | 60     Path clipPath; | 
| 59     if (m_clip.asPath(animatedLocalTransform, targetBoundingBox, clipPath)) { | 61     if (m_clip.asPath(animatedLocalTransform, targetBoundingBox, clipPath)) { | 
| 60         AffineTransform positionTransform; | 62         AffineTransform positionTransform; | 
| 61         positionTransform.translate(layerPositionOffset.x(), layerPositionOffset
     .y()); | 63         positionTransform.translate(layerPositionOffset.x(), layerPositionOffset
     .y()); | 
| 62         clipPath.transform(positionTransform); | 64         clipPath.transform(positionTransform); | 
| 63         clipperState = ClipperAppliedPath; | 65         clipperState = ClipperState::AppliedPath; | 
| 64         context.getPaintController().createAndAppend<BeginClipPathDisplayItem>(t
     arget, clipPath); | 66         context.getPaintController().createAndAppend<BeginClipPathDisplayItem>(t
     arget, clipPath); | 
| 65         return true; | 67         return true; | 
| 66     } | 68     } | 
| 67 | 69 | 
| 68     // Fall back to masking. | 70     // Fall back to masking. | 
| 69     clipperState = ClipperAppliedMask; | 71     clipperState = ClipperState::AppliedMask; | 
| 70 | 72 | 
| 71     // Begin compositing the clip mask. | 73     // Begin compositing the clip mask. | 
| 72     CompositingRecorder::beginCompositing(context, target, SkXfermode::kSrcOver_
     Mode, 1, &paintInvalidationRect); | 74     CompositingRecorder::beginCompositing(context, target, SkXfermode::kSrcOver_
     Mode, 1, &paintInvalidationRect); | 
| 73     { | 75     { | 
| 74         if (!drawClipAsMask(context, target, targetBoundingBox, paintInvalidatio
     nRect, animatedLocalTransform, layerPositionOffset)) { | 76         if (!drawClipAsMask(context, target, targetBoundingBox, paintInvalidatio
     nRect, animatedLocalTransform, layerPositionOffset)) { | 
| 75             // End the clip mask's compositor. | 77             // End the clip mask's compositor. | 
| 76             CompositingRecorder::endCompositing(context, target); | 78             CompositingRecorder::endCompositing(context, target); | 
| 77             return false; | 79             return false; | 
| 78         } | 80         } | 
| 79     } | 81     } | 
| 80 | 82 | 
| 81     // Masked content layer start. | 83     // Masked content layer start. | 
| 82     CompositingRecorder::beginCompositing(context, target, SkXfermode::kSrcIn_Mo
     de, 1, &paintInvalidationRect); | 84     CompositingRecorder::beginCompositing(context, target, SkXfermode::kSrcIn_Mo
     de, 1, &paintInvalidationRect); | 
| 83 | 85 | 
| 84     return true; | 86     return true; | 
| 85 } | 87 } | 
| 86 | 88 | 
| 87 void SVGClipPainter::finishEffect(const LayoutObject& target, GraphicsContext& c
     ontext, ClipperState& clipperState) | 89 void SVGClipPainter::finishEffect(const LayoutObject& target, GraphicsContext& c
     ontext, ClipperState& clipperState) | 
| 88 { | 90 { | 
| 89     switch (clipperState) { | 91     switch (clipperState) { | 
| 90     case ClipperAppliedPath: | 92     case ClipperState::AppliedPath: | 
| 91         // Path-only clipping, no layers to restore but we need to emit an end t
     o the clip path display item. | 93         // Path-only clipping, no layers to restore but we need to emit an end t
     o the clip path display item. | 
| 92         context.getPaintController().endItem<EndClipPathDisplayItem>(target); | 94         context.getPaintController().endItem<EndClipPathDisplayItem>(target); | 
| 93         break; | 95         break; | 
| 94     case ClipperAppliedMask: | 96     case ClipperState::AppliedMask: | 
| 95         // Transfer content -> clip mask (SrcIn) | 97         // Transfer content -> clip mask (SrcIn) | 
| 96         CompositingRecorder::endCompositing(context, target); | 98         CompositingRecorder::endCompositing(context, target); | 
| 97 | 99 | 
| 98         // Transfer clip mask -> bg (SrcOver) | 100         // Transfer clip mask -> bg (SrcOver) | 
| 99         CompositingRecorder::endCompositing(context, target); | 101         CompositingRecorder::endCompositing(context, target); | 
| 100         break; | 102         break; | 
| 101     default: | 103     default: | 
| 102         ASSERT_NOT_REACHED(); | 104         NOTREACHED(); | 
| 103     } | 105     } | 
| 104 } | 106 } | 
| 105 | 107 | 
| 106 bool SVGClipPainter::drawClipAsMask(GraphicsContext& context, const LayoutObject
     & layoutObject, const FloatRect& targetBoundingBox, | 108 bool SVGClipPainter::drawClipAsMask(GraphicsContext& context, const LayoutObject
     & layoutObject, const FloatRect& targetBoundingBox, | 
| 107     const FloatRect& targetPaintInvalidationRect, const AffineTransform& localTr
     ansform, const FloatPoint& layerPositionOffset) | 109     const FloatRect& targetPaintInvalidationRect, const AffineTransform& localTr
     ansform, const FloatPoint& layerPositionOffset) | 
| 108 { | 110 { | 
| 109     if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(context, layoutO
     bject, DisplayItem::kSVGClip)) | 111     if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(context, layoutO
     bject, DisplayItem::kSVGClip)) | 
| 110         return true; | 112         return true; | 
| 111 | 113 | 
| 112     SkPictureBuilder maskPictureBuilder(targetPaintInvalidationRect, nullptr, &c
     ontext); | 114     SkPictureBuilder maskPictureBuilder(targetPaintInvalidationRect, nullptr, &c
     ontext); | 
| 113     GraphicsContext& maskContext = maskPictureBuilder.context(); | 115     GraphicsContext& maskContext = maskPictureBuilder.context(); | 
| 114     { | 116     { | 
| 115         TransformRecorder recorder(maskContext, layoutObject, localTransform); | 117         TransformRecorder recorder(maskContext, layoutObject, localTransform); | 
| 116 | 118 | 
| 117         // Create a clipPathClipper if this clipPath is clipped by another clipP
     ath. | 119         // Apply any clip-path clipping this clipPath (nested shape/clipPath.) | 
| 118         SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObj
     ect(&m_clip); | 120         Optional<ClipPathClipper> nestedClipPathClipper; | 
| 119         LayoutSVGResourceClipper* clipPathClipper = resources ? resources->clipp
     er() : nullptr; | 121         if (ClipPathOperation* clipPathOperation = m_clip.styleRef().svgStyle().
     clipPath()) | 
| 120         ClipperState clipPathClipperState = ClipperNotApplied; | 122             nestedClipPathClipper.emplace(maskContext, *clipPathOperation, m_cli
     p, targetBoundingBox, layerPositionOffset); | 
| 121         if (clipPathClipper && !SVGClipPainter(*clipPathClipper).prepareEffect(m
     _clip, targetBoundingBox, targetPaintInvalidationRect, layerPositionOffset, mask
     Context, clipPathClipperState)) |  | 
| 122             return false; |  | 
| 123 | 123 | 
| 124         { | 124         { | 
| 125             AffineTransform contentTransform; | 125             AffineTransform contentTransform; | 
| 126             if (m_clip.clipPathUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundi
     ngbox) { | 126             if (m_clip.clipPathUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundi
     ngbox) { | 
| 127                 contentTransform.translate(targetBoundingBox.x(), targetBounding
     Box.y()); | 127                 contentTransform.translate(targetBoundingBox.x(), targetBounding
     Box.y()); | 
| 128                 contentTransform.scaleNonUniform(targetBoundingBox.width(), targ
     etBoundingBox.height()); | 128                 contentTransform.scaleNonUniform(targetBoundingBox.width(), targ
     etBoundingBox.height()); | 
| 129             } | 129             } | 
| 130             SubtreeContentTransformScope contentTransformScope(contentTransform)
     ; | 130             SubtreeContentTransformScope contentTransformScope(contentTransform)
     ; | 
| 131 | 131 | 
| 132             TransformRecorder contentTransformRecorder(maskContext, layoutObject
     , contentTransform); | 132             TransformRecorder contentTransformRecorder(maskContext, layoutObject
     , contentTransform); | 
| 133             maskContext.getPaintController().createAndAppend<DrawingDisplayItem>
     (layoutObject, DisplayItem::kSVGClip, m_clip.createContentPicture()); | 133             maskContext.getPaintController().createAndAppend<DrawingDisplayItem>
     (layoutObject, DisplayItem::kSVGClip, m_clip.createContentPicture()); | 
| 134         } | 134         } | 
| 135 |  | 
| 136         if (clipPathClipper) |  | 
| 137             SVGClipPainter(*clipPathClipper).finishEffect(m_clip, maskContext, c
     lipPathClipperState); |  | 
| 138     } | 135     } | 
| 139 | 136 | 
| 140     LayoutObjectDrawingRecorder drawingRecorder(context, layoutObject, DisplayIt
     em::kSVGClip, targetPaintInvalidationRect); | 137     LayoutObjectDrawingRecorder drawingRecorder(context, layoutObject, DisplayIt
     em::kSVGClip, targetPaintInvalidationRect); | 
| 141     sk_sp<SkPicture> maskPicture = maskPictureBuilder.endRecording(); | 138     sk_sp<SkPicture> maskPicture = maskPictureBuilder.endRecording(); | 
| 142     context.drawPicture(maskPicture.get()); | 139     context.drawPicture(maskPicture.get()); | 
| 143     return true; | 140     return true; | 
| 144 } | 141 } | 
| 145 | 142 | 
| 146 } // namespace blink | 143 } // namespace blink | 
| OLD | NEW | 
|---|