OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2004, 2005, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org> | 2 * Copyright (C) 2004, 2005, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org> |
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Rob Buis <buis@kde.org> | 3 * Copyright (C) 2004, 2005, 2006, 2007, 2008 Rob Buis <buis@kde.org> |
4 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. | 4 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. |
5 * Copyright (C) 2011 Dirk Schulze <krit@webkit.org> | 5 * Copyright (C) 2011 Dirk Schulze <krit@webkit.org> |
6 * | 6 * |
7 * This library is free software; you can redistribute it and/or | 7 * This library is free software; you can redistribute it and/or |
8 * modify it under the terms of the GNU Library General Public | 8 * modify it under the terms of the GNU Library General Public |
9 * License as published by the Free Software Foundation; either | 9 * License as published by the Free Software Foundation; either |
10 * version 2 of the License, or (at your option) any later version. | 10 * version 2 of the License, or (at your option) any later version. |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 ASSERT(client); | 56 ASSERT(client); |
57 markClientForInvalidation(client, markForInvalidation | 57 markClientForInvalidation(client, markForInvalidation |
58 ? BoundariesInvalidation | 58 ? BoundariesInvalidation |
59 : ParentOnlyInvalidation); | 59 : ParentOnlyInvalidation); |
60 } | 60 } |
61 | 61 |
62 bool LayoutSVGResourceClipper::calculateClipContentPathIfNeeded() { | 62 bool LayoutSVGResourceClipper::calculateClipContentPathIfNeeded() { |
63 if (!m_clipContentPath.isEmpty()) | 63 if (!m_clipContentPath.isEmpty()) |
64 return true; | 64 return true; |
65 | 65 |
66 // If the current clip-path gets clipped itself, we have to fallback to maskin
g. | 66 // If the current clip-path gets clipped itself, we have to fallback to |
| 67 // masking. |
67 if (styleRef().clipPath()) | 68 if (styleRef().clipPath()) |
68 return false; | 69 return false; |
69 | 70 |
70 unsigned opCount = 0; | 71 unsigned opCount = 0; |
71 bool usingBuilder = false; | 72 bool usingBuilder = false; |
72 SkOpBuilder clipPathBuilder; | 73 SkOpBuilder clipPathBuilder; |
73 | 74 |
74 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); | 75 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); |
75 childElement; | 76 childElement; |
76 childElement = Traversal<SVGElement>::nextSibling(*childElement)) { | 77 childElement = Traversal<SVGElement>::nextSibling(*childElement)) { |
77 LayoutObject* childLayoutObject = childElement->layoutObject(); | 78 LayoutObject* childLayoutObject = childElement->layoutObject(); |
78 if (!childLayoutObject) | 79 if (!childLayoutObject) |
79 continue; | 80 continue; |
80 // Only shapes or paths are supported for direct clipping. We need to fallba
ck to masking for texts. | 81 // Only shapes or paths are supported for direct clipping. We need to |
| 82 // fallback to masking for texts. |
81 if (childLayoutObject->isSVGText()) { | 83 if (childLayoutObject->isSVGText()) { |
82 m_clipContentPath.clear(); | 84 m_clipContentPath.clear(); |
83 return false; | 85 return false; |
84 } | 86 } |
85 if (!childElement->isSVGGraphicsElement()) | 87 if (!childElement->isSVGGraphicsElement()) |
86 continue; | 88 continue; |
87 | 89 |
88 const ComputedStyle* style = childLayoutObject->style(); | 90 const ComputedStyle* style = childLayoutObject->style(); |
89 if (!style || style->display() == EDisplay::None || | 91 if (!style || style->display() == EDisplay::None || |
90 (style->visibility() != EVisibility::Visible && | 92 (style->visibility() != EVisibility::Visible && |
91 !isSVGUseElement(*childElement))) | 93 !isSVGUseElement(*childElement))) |
92 continue; | 94 continue; |
93 | 95 |
94 // Current shape in clip-path gets clipped too. Fallback to masking. | 96 // Current shape in clip-path gets clipped too. Fallback to masking. |
95 if (style->clipPath()) { | 97 if (style->clipPath()) { |
96 m_clipContentPath.clear(); | 98 m_clipContentPath.clear(); |
97 return false; | 99 return false; |
98 } | 100 } |
99 | 101 |
100 // First clip shape. | 102 // First clip shape. |
101 if (m_clipContentPath.isEmpty()) { | 103 if (m_clipContentPath.isEmpty()) { |
102 if (isSVGGeometryElement(childElement)) | 104 if (isSVGGeometryElement(childElement)) |
103 toSVGGeometryElement(childElement)->toClipPath(m_clipContentPath); | 105 toSVGGeometryElement(childElement)->toClipPath(m_clipContentPath); |
104 else if (isSVGUseElement(childElement)) | 106 else if (isSVGUseElement(childElement)) |
105 toSVGUseElement(childElement)->toClipPath(m_clipContentPath); | 107 toSVGUseElement(childElement)->toClipPath(m_clipContentPath); |
106 | 108 |
107 continue; | 109 continue; |
108 } | 110 } |
109 | 111 |
110 // Multiple shapes require PathOps. In some degenerate cases PathOps can exh
ibit quadratic | 112 // Multiple shapes require PathOps. In some degenerate cases PathOps can |
111 // behavior, so we cap the number of ops to a reasonable count. | 113 // exhibit quadratic behavior, so we cap the number of ops to a reasonable |
| 114 // count. |
112 const unsigned kMaxOps = 42; | 115 const unsigned kMaxOps = 42; |
113 if (++opCount > kMaxOps) { | 116 if (++opCount > kMaxOps) { |
114 m_clipContentPath.clear(); | 117 m_clipContentPath.clear(); |
115 return false; | 118 return false; |
116 } | 119 } |
117 | 120 |
118 // Second clip shape => start using the builder. | 121 // Second clip shape => start using the builder. |
119 if (!usingBuilder) { | 122 if (!usingBuilder) { |
120 clipPathBuilder.add(m_clipContentPath.getSkPath(), kUnion_SkPathOp); | 123 clipPathBuilder.add(m_clipContentPath.getSkPath(), kUnion_SkPathOp); |
121 usingBuilder = true; | 124 usingBuilder = true; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 // Transform path by animatedLocalTransform. | 163 // Transform path by animatedLocalTransform. |
161 clipPath.transform(animatedLocalTransform); | 164 clipPath.transform(animatedLocalTransform); |
162 return true; | 165 return true; |
163 } | 166 } |
164 | 167 |
165 sk_sp<const SkPicture> LayoutSVGResourceClipper::createContentPicture() { | 168 sk_sp<const SkPicture> LayoutSVGResourceClipper::createContentPicture() { |
166 ASSERT(frame()); | 169 ASSERT(frame()); |
167 if (m_clipContentPicture) | 170 if (m_clipContentPicture) |
168 return m_clipContentPicture; | 171 return m_clipContentPicture; |
169 | 172 |
170 // Using strokeBoundingBox (instead of paintInvalidationRectInLocalSVGCoordina
tes) to avoid the intersection | 173 // Using strokeBoundingBox (instead of |
171 // with local clips/mask, which may yield incorrect results when mixing object
BoundingBox and | 174 // paintInvalidationRectInLocalSVGCoordinates) to avoid the intersection with |
172 // userSpaceOnUse units (http://crbug.com/294900). | 175 // local clips/mask, which may yield incorrect results when mixing |
| 176 // objectBoundingBox and userSpaceOnUse units (http://crbug.com/294900). |
173 FloatRect bounds = strokeBoundingBox(); | 177 FloatRect bounds = strokeBoundingBox(); |
174 | 178 |
175 SkPictureBuilder pictureBuilder(bounds, nullptr, nullptr); | 179 SkPictureBuilder pictureBuilder(bounds, nullptr, nullptr); |
176 | 180 |
177 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); | 181 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); |
178 childElement; | 182 childElement; |
179 childElement = Traversal<SVGElement>::nextSibling(*childElement)) { | 183 childElement = Traversal<SVGElement>::nextSibling(*childElement)) { |
180 LayoutObject* layoutObject = childElement->layoutObject(); | 184 LayoutObject* layoutObject = childElement->layoutObject(); |
181 if (!layoutObject) | 185 if (!layoutObject) |
182 continue; | 186 continue; |
(...skipping 17 matching lines...) Expand all Loading... |
200 continue; | 204 continue; |
201 } | 205 } |
202 | 206 |
203 // Only shapes, paths and texts are allowed for clipping. | 207 // Only shapes, paths and texts are allowed for clipping. |
204 if (!layoutObject->isSVGShape() && !layoutObject->isSVGText()) | 208 if (!layoutObject->isSVGShape() && !layoutObject->isSVGText()) |
205 continue; | 209 continue; |
206 | 210 |
207 if (isUseElement) | 211 if (isUseElement) |
208 layoutObject = childElement->layoutObject(); | 212 layoutObject = childElement->layoutObject(); |
209 | 213 |
210 // Switch to a paint behavior where all children of this <clipPath> will be
laid out using special constraints: | 214 // Switch to a paint behavior where all children of this <clipPath> will be |
| 215 // laid out using special constraints: |
211 // - fill-opacity/stroke-opacity/opacity set to 1 | 216 // - fill-opacity/stroke-opacity/opacity set to 1 |
212 // - masker/filter not applied when laying out the children | 217 // - masker/filter not applied when laying out the children |
213 // - fill is set to the initial fill paint server (solid, black) | 218 // - fill is set to the initial fill paint server (solid, black) |
214 // - stroke is set to the initial stroke paint server (none) | 219 // - stroke is set to the initial stroke paint server (none) |
215 PaintInfo info(pictureBuilder.context(), LayoutRect::infiniteIntRect(), | 220 PaintInfo info(pictureBuilder.context(), LayoutRect::infiniteIntRect(), |
216 PaintPhaseForeground, GlobalPaintNormalPhase, | 221 PaintPhaseForeground, GlobalPaintNormalPhase, |
217 PaintLayerPaintingRenderingClipPathAsMask); | 222 PaintLayerPaintingRenderingClipPathAsMask); |
218 layoutObject->paint(info, IntPoint()); | 223 layoutObject->paint(info, IntPoint()); |
219 } | 224 } |
220 | 225 |
221 m_clipContentPicture = pictureBuilder.endRecording(); | 226 m_clipContentPicture = pictureBuilder.endRecording(); |
222 return m_clipContentPicture; | 227 return m_clipContentPicture; |
223 } | 228 } |
224 | 229 |
225 void LayoutSVGResourceClipper::calculateLocalClipBounds() { | 230 void LayoutSVGResourceClipper::calculateLocalClipBounds() { |
226 // This is a rough heuristic to appraise the clip size and doesn't consider cl
ip on clip. | 231 // This is a rough heuristic to appraise the clip size and doesn't consider |
| 232 // clip on clip. |
227 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); | 233 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); |
228 childElement; | 234 childElement; |
229 childElement = Traversal<SVGElement>::nextSibling(*childElement)) { | 235 childElement = Traversal<SVGElement>::nextSibling(*childElement)) { |
230 LayoutObject* layoutObject = childElement->layoutObject(); | 236 LayoutObject* layoutObject = childElement->layoutObject(); |
231 if (!layoutObject) | 237 if (!layoutObject) |
232 continue; | 238 continue; |
233 if (!layoutObject->isSVGShape() && !layoutObject->isSVGText() && | 239 if (!layoutObject->isSVGShape() && !layoutObject->isSVGText() && |
234 !isSVGUseElement(*childElement)) | 240 !isSVGUseElement(*childElement)) |
235 continue; | 241 continue; |
236 const ComputedStyle* style = layoutObject->style(); | 242 const ComputedStyle* style = layoutObject->style(); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 AffineTransform transform = | 306 AffineTransform transform = |
301 toSVGClipPathElement(element())->calculateAnimatedLocalTransform(); | 307 toSVGClipPathElement(element())->calculateAnimatedLocalTransform(); |
302 if (clipPathUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) { | 308 if (clipPathUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) { |
303 transform.translate(referenceBox.x(), referenceBox.y()); | 309 transform.translate(referenceBox.x(), referenceBox.y()); |
304 transform.scaleNonUniform(referenceBox.width(), referenceBox.height()); | 310 transform.scaleNonUniform(referenceBox.width(), referenceBox.height()); |
305 } | 311 } |
306 return transform.mapRect(m_localClipBounds); | 312 return transform.mapRect(m_localClipBounds); |
307 } | 313 } |
308 | 314 |
309 } // namespace blink | 315 } // namespace blink |
OLD | NEW |