| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "core/paint/SVGClipPainter.h" | |
| 6 | |
| 7 #include "core/dom/ElementTraversal.h" | |
| 8 #include "core/layout/svg/LayoutSVGResourceClipper.h" | |
| 9 #include "core/layout/svg/SVGLayoutSupport.h" | |
| 10 #include "core/layout/svg/SVGResources.h" | |
| 11 #include "core/layout/svg/SVGResourcesCache.h" | |
| 12 #include "core/paint/ClipPathClipper.h" | |
| 13 #include "core/paint/LayoutObjectDrawingRecorder.h" | |
| 14 #include "core/paint/PaintInfo.h" | |
| 15 #include "core/paint/TransformRecorder.h" | |
| 16 #include "platform/graphics/paint/ClipPathDisplayItem.h" | |
| 17 #include "platform/graphics/paint/ClipPathRecorder.h" | |
| 18 #include "platform/graphics/paint/CompositingRecorder.h" | |
| 19 #include "platform/graphics/paint/DrawingDisplayItem.h" | |
| 20 #include "platform/graphics/paint/PaintController.h" | |
| 21 #include "platform/graphics/paint/PaintRecordBuilder.h" | |
| 22 | |
| 23 namespace blink { | |
| 24 | |
| 25 namespace { | |
| 26 | |
| 27 class SVGClipExpansionCycleHelper { | |
| 28 public: | |
| 29 SVGClipExpansionCycleHelper(LayoutSVGResourceClipper& clip) : m_clip(clip) { | |
| 30 clip.beginClipExpansion(); | |
| 31 } | |
| 32 ~SVGClipExpansionCycleHelper() { m_clip.endClipExpansion(); } | |
| 33 | |
| 34 private: | |
| 35 LayoutSVGResourceClipper& m_clip; | |
| 36 }; | |
| 37 | |
| 38 } // namespace | |
| 39 | |
| 40 bool SVGClipPainter::prepareEffect(const LayoutObject& target, | |
| 41 const FloatRect& targetBoundingBox, | |
| 42 const FloatRect& visualRect, | |
| 43 const FloatPoint& layerPositionOffset, | |
| 44 GraphicsContext& context, | |
| 45 ClipperState& clipperState) { | |
| 46 DCHECK_EQ(clipperState, ClipperState::NotApplied); | |
| 47 SECURITY_DCHECK(!m_clip.needsLayout()); | |
| 48 | |
| 49 m_clip.clearInvalidationMask(); | |
| 50 | |
| 51 if (m_clip.hasCycle()) | |
| 52 return false; | |
| 53 | |
| 54 SVGClipExpansionCycleHelper inClipExpansionChange(m_clip); | |
| 55 | |
| 56 AffineTransform animatedLocalTransform = | |
| 57 toSVGClipPathElement(m_clip.element()) | |
| 58 ->calculateTransform(SVGElement::IncludeMotionTransform); | |
| 59 // When drawing a clip for non-SVG elements, the CTM does not include the zoom | |
| 60 // factor. In this case, we need to apply the zoom scale explicitly - but | |
| 61 // only for clips with userSpaceOnUse units (the zoom is accounted for | |
| 62 // objectBoundingBox-resolved lengths). | |
| 63 if (!target.isSVG() && | |
| 64 m_clip.clipPathUnits() == SVGUnitTypes::kSvgUnitTypeUserspaceonuse) { | |
| 65 DCHECK(m_clip.style()); | |
| 66 animatedLocalTransform.scale(m_clip.style()->effectiveZoom()); | |
| 67 } | |
| 68 | |
| 69 // First, try to apply the clip as a clipPath. | |
| 70 Path clipPath; | |
| 71 if (m_clip.asPath(animatedLocalTransform, targetBoundingBox, clipPath)) { | |
| 72 AffineTransform positionTransform; | |
| 73 positionTransform.translate(layerPositionOffset.x(), | |
| 74 layerPositionOffset.y()); | |
| 75 clipPath.transform(positionTransform); | |
| 76 clipperState = ClipperState::AppliedPath; | |
| 77 context.getPaintController().createAndAppend<BeginClipPathDisplayItem>( | |
| 78 target, clipPath); | |
| 79 return true; | |
| 80 } | |
| 81 | |
| 82 // Fall back to masking. | |
| 83 clipperState = ClipperState::AppliedMask; | |
| 84 | |
| 85 // Begin compositing the clip mask. | |
| 86 CompositingRecorder::beginCompositing(context, target, SkBlendMode::kSrcOver, | |
| 87 1, &visualRect); | |
| 88 { | |
| 89 if (!drawClipAsMask(context, target, targetBoundingBox, visualRect, | |
| 90 animatedLocalTransform, layerPositionOffset)) { | |
| 91 // End the clip mask's compositor. | |
| 92 CompositingRecorder::endCompositing(context, target); | |
| 93 return false; | |
| 94 } | |
| 95 } | |
| 96 | |
| 97 // Masked content layer start. | |
| 98 CompositingRecorder::beginCompositing(context, target, SkBlendMode::kSrcIn, 1, | |
| 99 &visualRect); | |
| 100 | |
| 101 return true; | |
| 102 } | |
| 103 | |
| 104 void SVGClipPainter::finishEffect(const LayoutObject& target, | |
| 105 GraphicsContext& context, | |
| 106 ClipperState& clipperState) { | |
| 107 switch (clipperState) { | |
| 108 case ClipperState::AppliedPath: | |
| 109 // Path-only clipping, no layers to restore but we need to emit an end to | |
| 110 // the clip path display item. | |
| 111 context.getPaintController().endItem<EndClipPathDisplayItem>(target); | |
| 112 break; | |
| 113 case ClipperState::AppliedMask: | |
| 114 // Transfer content -> clip mask (SrcIn) | |
| 115 CompositingRecorder::endCompositing(context, target); | |
| 116 | |
| 117 // Transfer clip mask -> bg (SrcOver) | |
| 118 CompositingRecorder::endCompositing(context, target); | |
| 119 break; | |
| 120 default: | |
| 121 NOTREACHED(); | |
| 122 } | |
| 123 } | |
| 124 | |
| 125 bool SVGClipPainter::drawClipAsMask(GraphicsContext& context, | |
| 126 const LayoutObject& layoutObject, | |
| 127 const FloatRect& targetBoundingBox, | |
| 128 const FloatRect& targetVisualRect, | |
| 129 const AffineTransform& localTransform, | |
| 130 const FloatPoint& layerPositionOffset) { | |
| 131 if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible( | |
| 132 context, layoutObject, DisplayItem::kSVGClip)) | |
| 133 return true; | |
| 134 | |
| 135 PaintRecordBuilder maskBuilder(targetVisualRect, nullptr, &context); | |
| 136 GraphicsContext& maskContext = maskBuilder.context(); | |
| 137 { | |
| 138 TransformRecorder recorder(maskContext, layoutObject, localTransform); | |
| 139 | |
| 140 // Apply any clip-path clipping this clipPath (nested shape/clipPath.) | |
| 141 Optional<ClipPathClipper> nestedClipPathClipper; | |
| 142 if (ClipPathOperation* clipPathOperation = m_clip.styleRef().clipPath()) | |
| 143 nestedClipPathClipper.emplace(maskContext, *clipPathOperation, m_clip, | |
| 144 targetBoundingBox, layerPositionOffset); | |
| 145 | |
| 146 { | |
| 147 AffineTransform contentTransform; | |
| 148 if (m_clip.clipPathUnits() == | |
| 149 SVGUnitTypes::kSvgUnitTypeObjectboundingbox) { | |
| 150 contentTransform.translate(targetBoundingBox.x(), | |
| 151 targetBoundingBox.y()); | |
| 152 contentTransform.scaleNonUniform(targetBoundingBox.width(), | |
| 153 targetBoundingBox.height()); | |
| 154 } | |
| 155 SubtreeContentTransformScope contentTransformScope(contentTransform); | |
| 156 | |
| 157 TransformRecorder contentTransformRecorder(maskContext, layoutObject, | |
| 158 contentTransform); | |
| 159 maskContext.getPaintController().createAndAppend<DrawingDisplayItem>( | |
| 160 layoutObject, DisplayItem::kSVGClip, m_clip.createPaintRecord()); | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 LayoutObjectDrawingRecorder drawingRecorder( | |
| 165 context, layoutObject, DisplayItem::kSVGClip, targetVisualRect); | |
| 166 sk_sp<PaintRecord> maskPaintRecord = maskBuilder.endRecording(); | |
| 167 context.drawRecord(maskPaintRecord.get()); | |
| 168 return true; | |
| 169 } | |
| 170 | |
| 171 } // namespace blink | |
| OLD | NEW |