Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(57)

Side by Side Diff: Source/core/layout/svg/LayoutSVGResourceClipper.cpp

Issue 1174393003: Unify content transformation calculations for SVG clip paths (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Rebase Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
59 m_clipBoundaries = FloatRect(); 59 m_clipBoundaries = FloatRect();
60 markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInval idation : ParentOnlyInvalidation); 60 markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInval idation : ParentOnlyInvalidation);
61 } 61 }
62 62
63 void LayoutSVGResourceClipper::removeClientFromCache(LayoutObject* client, bool markForInvalidation) 63 void LayoutSVGResourceClipper::removeClientFromCache(LayoutObject* client, bool markForInvalidation)
64 { 64 {
65 ASSERT(client); 65 ASSERT(client);
66 markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidati on : ParentOnlyInvalidation); 66 markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidati on : ParentOnlyInvalidation);
67 } 67 }
68 68
69 AffineTransform LayoutSVGResourceClipper::calculateContentTransformation(const L ayoutObject* target, const FloatRect& targetBoundingBox)
fs 2015/06/16 09:30:15 const?
70 {
71 AffineTransform transform = toSVGClipPathElement(element())->calculateAnimat edLocalTransform();
72
73 // When drawing a clip for non-SVG elements, the CTM does not include the zo om factor.
74 // In this case, we need to apply the zoom scale explicitly - but only for c lips with
75 // userSpaceOnUse units (the zoom is accounted for objectBoundingBox-resolve d lengths).
76 if (target && !target->isSVG() && clipPathUnits() == SVGUnitTypes::SVG_UNIT_ TYPE_USERSPACEONUSE)
77 transform.scale(style()->effectiveZoom());
fs 2015/06/16 09:30:15 Shouldn't this apply before 'transform'?
78
79 if (clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
80 transform.translate(targetBoundingBox.x(), targetBoundingBox.y());
81 transform.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.h eight());
82 }
83
84 return transform;
85 }
86
69 bool LayoutSVGResourceClipper::tryPathOnlyClipping(const LayoutObject& layoutObj ect, GraphicsContext* context, 87 bool LayoutSVGResourceClipper::tryPathOnlyClipping(const LayoutObject& layoutObj ect, GraphicsContext* context,
70 const AffineTransform& animatedLocalTransform, const FloatRect& objectBoundi ngBox) { 88 const AffineTransform& contentTransformation) {
71 // If the current clip-path gets clipped itself, we have to fallback to mask ing. 89 // If the current clip-path gets clipped itself, we have to fallback to mask ing.
72 if (!style()->svgStyle().clipperResource().isEmpty()) 90 if (!style()->svgStyle().clipperResource().isEmpty())
73 return false; 91 return false;
74 92
75 Path clipPath; 93 Path clipPath;
76 94
77 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element() ); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement )) { 95 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element() ); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement )) {
78 LayoutObject* childLayoutObject = childElement->layoutObject(); 96 LayoutObject* childLayoutObject = childElement->layoutObject();
79 if (!childLayoutObject) 97 if (!childLayoutObject)
80 continue; 98 continue;
(...skipping 23 matching lines...) Expand all
104 styled->toClipPath(subPath); 122 styled->toClipPath(subPath);
105 if (!clipPath.unionPath(subPath)) 123 if (!clipPath.unionPath(subPath))
106 return false; 124 return false;
107 } else { 125 } else {
108 return false; 126 return false;
109 } 127 }
110 } 128 }
111 129
112 // We are able to represent the clip as a path. Continue with direct clippin g, 130 // We are able to represent the clip as a path. Continue with direct clippin g,
113 // and transform the content to userspace if necessary. 131 // and transform the content to userspace if necessary.
114 if (clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { 132 clipPath.transform(contentTransformation);
115 AffineTransform transform;
116 transform.translate(objectBoundingBox.x(), objectBoundingBox.y());
117 transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.h eight());
118 clipPath.transform(transform);
119 }
120
121 // Transform path by animatedLocalTransform.
122 clipPath.transform(animatedLocalTransform);
123 133
124 if (RuntimeEnabledFeatures::slimmingPaintEnabled()) { 134 if (RuntimeEnabledFeatures::slimmingPaintEnabled()) {
125 if (!context->displayItemList()->displayItemConstructionIsDisabled()) 135 if (!context->displayItemList()->displayItemConstructionIsDisabled())
126 context->displayItemList()->add(BeginClipPathDisplayItem::create(lay outObject, clipPath)); 136 context->displayItemList()->add(BeginClipPathDisplayItem::create(lay outObject, clipPath));
127 } else { 137 } else {
128 BeginClipPathDisplayItem clipPathDisplayItem(layoutObject, clipPath); 138 BeginClipPathDisplayItem clipPathDisplayItem(layoutObject, clipPath);
129 clipPathDisplayItem.replay(*context); 139 clipPathDisplayItem.replay(*context);
130 } 140 }
131 141
132 return true; 142 return true;
133 } 143 }
134 144
135 PassRefPtr<const SkPicture> LayoutSVGResourceClipper::createContentPicture(Affin eTransform& contentTransformation, const FloatRect& targetBoundingBox, 145 PassRefPtr<const SkPicture> LayoutSVGResourceClipper::createContentPicture(const AffineTransform& contentTransformation, GraphicsContext* context)
136 GraphicsContext* context)
137 { 146 {
138 ASSERT(frame()); 147 ASSERT(frame());
139 148
140 if (clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
141 contentTransformation.translate(targetBoundingBox.x(), targetBoundingBox .y());
142 contentTransformation.scaleNonUniform(targetBoundingBox.width(), targetB oundingBox.height());
143 }
144
145 if (m_clipContentPicture) 149 if (m_clipContentPicture)
146 return m_clipContentPicture; 150 return m_clipContentPicture;
147 151
148 SubtreeContentTransformScope contentTransformScope(contentTransformation); 152 SubtreeContentTransformScope contentTransformScope(contentTransformation);
149 153
150 // Using strokeBoundingBox (instead of paintInvalidationRectInLocalCoordinat es) to avoid the intersection 154 // Using strokeBoundingBox (instead of paintInvalidationRectInLocalCoordinat es) to avoid the intersection
151 // with local clips/mask, which may yield incorrect results when mixing obje ctBoundingBox and 155 // with local clips/mask, which may yield incorrect results when mixing obje ctBoundingBox and
152 // userSpaceOnUse units (http://crbug.com/294900). 156 // userSpaceOnUse units (http://crbug.com/294900).
153 FloatRect bounds = strokeBoundingBox(); 157 FloatRect bounds = strokeBoundingBox();
154 158
(...skipping 28 matching lines...) Expand all
183 // - fill is set to the initial fill paint server (solid, black) 187 // - fill is set to the initial fill paint server (solid, black)
184 // - stroke is set to the initial stroke paint server (none) 188 // - stroke is set to the initial stroke paint server (none)
185 PaintInfo info(&pictureBuilder.context(), LayoutRect::infiniteIntRect(), PaintPhaseForeground, PaintBehaviorRenderingClipPathAsMask); 189 PaintInfo info(&pictureBuilder.context(), LayoutRect::infiniteIntRect(), PaintPhaseForeground, PaintBehaviorRenderingClipPathAsMask);
186 layoutObject->paint(info, IntPoint()); 190 layoutObject->paint(info, IntPoint());
187 } 191 }
188 192
189 m_clipContentPicture = pictureBuilder.endRecording(); 193 m_clipContentPicture = pictureBuilder.endRecording();
190 return m_clipContentPicture; 194 return m_clipContentPicture;
191 } 195 }
192 196
193 void LayoutSVGResourceClipper::calculateClipContentPaintInvalidationRect() 197 void LayoutSVGResourceClipper::calculateClipContentPaintInvalidationRect(const L ayoutObject* object)
194 { 198 {
195 // This is a rough heuristic to appraise the clip size and doesn't consider clip on clip. 199 // This is a rough heuristic to appraise the clip size and doesn't consider clip on clip.
196 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element() ); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement )) { 200 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element() ); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement )) {
197 LayoutObject* layoutObject = childElement->layoutObject(); 201 LayoutObject* layoutObject = childElement->layoutObject();
198 if (!layoutObject) 202 if (!layoutObject)
199 continue; 203 continue;
200 if (!layoutObject->isSVGShape() && !layoutObject->isSVGText() && !isSVGU seElement(*childElement)) 204 if (!layoutObject->isSVGShape() && !layoutObject->isSVGText() && !isSVGU seElement(*childElement))
201 continue; 205 continue;
202 const ComputedStyle* style = layoutObject->style(); 206 const ComputedStyle* style = layoutObject->style();
203 if (!style || style->display() == NONE || style->visibility() != VISIBLE ) 207 if (!style || style->display() == NONE || style->visibility() != VISIBLE )
204 continue; 208 continue;
205 m_clipBoundaries.unite(layoutObject->localToParentTransform().mapRect(la youtObject->paintInvalidationRectInLocalCoordinates())); 209 m_clipBoundaries.unite(layoutObject->localToParentTransform().mapRect(la youtObject->paintInvalidationRectInLocalCoordinates()));
206 } 210 }
207 m_clipBoundaries = toSVGClipPathElement(element())->calculateAnimatedLocalTr ansform().mapRect(m_clipBoundaries); 211
212 const AffineTransform& contentTransformation = calculateContentTransformatio n(object, object->objectBoundingBox());
213 m_clipBoundaries = contentTransformation.mapRect(m_clipBoundaries);
fs 2015/06/16 09:30:15 This makes m_clipBoundaries depend on a certain cl
208 } 214 }
209 215
210 bool LayoutSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundin gBox, const FloatPoint& nodeAtPoint) 216 bool LayoutSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundin gBox, const FloatPoint& nodeAtPoint)
211 { 217 {
212 FloatPoint point = nodeAtPoint; 218 FloatPoint point = nodeAtPoint;
213 if (!SVGLayoutSupport::pointInClippingArea(this, point)) 219 if (!SVGLayoutSupport::pointInClippingArea(this, point))
214 return false; 220 return false;
215 221
216 if (clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { 222 AffineTransform contentTransformation = calculateContentTransformation(nullp tr, objectBoundingBox);
217 AffineTransform transform; 223 contentTransformation.inverse().mapPoint(point);
fs 2015/06/16 09:30:15 point = ...
218 transform.translate(objectBoundingBox.x(), objectBoundingBox.y());
219 transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.h eight());
220 point = transform.inverse().mapPoint(point);
221 }
222
223 AffineTransform animatedLocalTransform = toSVGClipPathElement(element())->ca lculateAnimatedLocalTransform();
224 if (!animatedLocalTransform.isInvertible())
fs 2015/06/16 09:30:15 This got dropped.
225 return false;
226
227 point = animatedLocalTransform.inverse().mapPoint(point);
228 224
229 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element() ); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement )) { 225 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element() ); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement )) {
230 LayoutObject* layoutObject = childElement->layoutObject(); 226 LayoutObject* layoutObject = childElement->layoutObject();
231 if (!layoutObject) 227 if (!layoutObject)
232 continue; 228 continue;
233 if (!layoutObject->isSVGShape() && !layoutObject->isSVGText() && !isSVGU seElement(*childElement)) 229 if (!layoutObject->isSVGShape() && !layoutObject->isSVGText() && !isSVGU seElement(*childElement))
234 continue; 230 continue;
235 IntPoint hitPoint; 231 IntPoint hitPoint;
236 HitTestResult result(HitTestRequest::SVGClipContent, hitPoint); 232 HitTestResult result(HitTestRequest::SVGClipContent, hitPoint);
237 if (layoutObject->nodeAtFloatPoint(result, point, HitTestForeground)) 233 if (layoutObject->nodeAtFloatPoint(result, point, HitTestForeground))
238 return true; 234 return true;
239 } 235 }
240 236
241 return false; 237 return false;
242 } 238 }
243 239
244 FloatRect LayoutSVGResourceClipper::resourceBoundingBox(const LayoutObject* obje ct) 240 FloatRect LayoutSVGResourceClipper::resourceBoundingBox(const LayoutObject* obje ct)
245 { 241 {
246 // Resource was not layouted yet. Give back the boundingBox of the object. 242 // Resource was not layouted yet. Give back the boundingBox of the object.
247 if (selfNeedsLayout()) 243 if (selfNeedsLayout())
248 return object->objectBoundingBox(); 244 return object->objectBoundingBox();
249 245
250 if (m_clipBoundaries.isEmpty()) 246 if (m_clipBoundaries.isEmpty())
251 calculateClipContentPaintInvalidationRect(); 247 calculateClipContentPaintInvalidationRect(object);
252
253 if (clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
254 FloatRect objectBoundingBox = object->objectBoundingBox();
255 AffineTransform transform;
256 transform.translate(objectBoundingBox.x(), objectBoundingBox.y());
257 transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.h eight());
258 return transform.mapRect(m_clipBoundaries);
259 }
260 248
261 return m_clipBoundaries; 249 return m_clipBoundaries;
262 } 250 }
263 251
264 } 252 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698