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 |