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 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
51 { | 51 { |
52 } | 52 } |
53 | 53 |
54 void RenderSVGResourceClipper::removeAllClientsFromCache(bool markForInvalidatio
n) | 54 void RenderSVGResourceClipper::removeAllClientsFromCache(bool markForInvalidatio
n) |
55 { | 55 { |
56 m_clipContentPicture.clear(); | 56 m_clipContentPicture.clear(); |
57 m_clipBoundaries = FloatRect(); | 57 m_clipBoundaries = FloatRect(); |
58 markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInval
idation : ParentOnlyInvalidation); | 58 markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInval
idation : ParentOnlyInvalidation); |
59 } | 59 } |
60 | 60 |
61 void RenderSVGResourceClipper::removeClientFromCache(RenderObject* client, bool
markForInvalidation) | 61 void RenderSVGResourceClipper::removeClientFromCache(LayoutObject* client, bool
markForInvalidation) |
62 { | 62 { |
63 ASSERT(client); | 63 ASSERT(client); |
64 markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidati
on : ParentOnlyInvalidation); | 64 markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidati
on : ParentOnlyInvalidation); |
65 } | 65 } |
66 | 66 |
67 bool RenderSVGResourceClipper::applyStatefulResource(RenderObject* object, Graph
icsContext*& context, ClipperState& clipperState) | 67 bool RenderSVGResourceClipper::applyStatefulResource(LayoutObject* object, Graph
icsContext*& context, ClipperState& clipperState) |
68 { | 68 { |
69 ASSERT(object); | 69 ASSERT(object); |
70 ASSERT(context); | 70 ASSERT(context); |
71 | 71 |
72 clearInvalidationMask(); | 72 clearInvalidationMask(); |
73 | 73 |
74 return applyClippingToContext(object, object->objectBoundingBox(), object->p
aintInvalidationRectInLocalCoordinates(), context, clipperState); | 74 return applyClippingToContext(object, object->objectBoundingBox(), object->p
aintInvalidationRectInLocalCoordinates(), context, clipperState); |
75 } | 75 } |
76 | 76 |
77 bool RenderSVGResourceClipper::tryPathOnlyClipping(DisplayItemClient client, Gra
phicsContext* context, | 77 bool RenderSVGResourceClipper::tryPathOnlyClipping(DisplayItemClient client, Gra
phicsContext* context, |
78 const AffineTransform& animatedLocalTransform, const FloatRect& objectBoundi
ngBox) { | 78 const AffineTransform& animatedLocalTransform, const FloatRect& objectBoundi
ngBox) { |
79 // If the current clip-path gets clipped itself, we have to fallback to mask
ing. | 79 // If the current clip-path gets clipped itself, we have to fallback to mask
ing. |
80 if (!style()->svgStyle().clipperResource().isEmpty()) | 80 if (!style()->svgStyle().clipperResource().isEmpty()) |
81 return false; | 81 return false; |
82 WindRule clipRule = RULE_NONZERO; | 82 WindRule clipRule = RULE_NONZERO; |
83 Path clipPath = Path(); | 83 Path clipPath = Path(); |
84 | 84 |
85 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()
); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement
)) { | 85 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()
); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement
)) { |
86 RenderObject* renderer = childElement->renderer(); | 86 LayoutObject* renderer = childElement->renderer(); |
87 if (!renderer) | 87 if (!renderer) |
88 continue; | 88 continue; |
89 // Only shapes or paths are supported for direct clipping. We need to fa
llback to masking for texts. | 89 // Only shapes or paths are supported for direct clipping. We need to fa
llback to masking for texts. |
90 if (renderer->isSVGText()) | 90 if (renderer->isSVGText()) |
91 return false; | 91 return false; |
92 if (!childElement->isSVGGraphicsElement()) | 92 if (!childElement->isSVGGraphicsElement()) |
93 continue; | 93 continue; |
94 SVGGraphicsElement* styled = toSVGGraphicsElement(childElement); | 94 SVGGraphicsElement* styled = toSVGGraphicsElement(childElement); |
95 RenderStyle* style = renderer->style(); | 95 RenderStyle* style = renderer->style(); |
96 if (!style || style->display() == NONE || style->visibility() != VISIBLE
) | 96 if (!style || style->display() == NONE || style->visibility() != VISIBLE
) |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
137 if (RuntimeEnabledFeatures::slimmingPaintEnabled()) { | 137 if (RuntimeEnabledFeatures::slimmingPaintEnabled()) { |
138 context->displayItemList()->add(BeginClipPathDisplayItem::create(client,
clipPath, clipRule)); | 138 context->displayItemList()->add(BeginClipPathDisplayItem::create(client,
clipPath, clipRule)); |
139 } else { | 139 } else { |
140 BeginClipPathDisplayItem clipPathDisplayItem(client, clipPath, clipRule)
; | 140 BeginClipPathDisplayItem clipPathDisplayItem(client, clipPath, clipRule)
; |
141 clipPathDisplayItem.replay(context); | 141 clipPathDisplayItem.replay(context); |
142 } | 142 } |
143 | 143 |
144 return true; | 144 return true; |
145 } | 145 } |
146 | 146 |
147 bool RenderSVGResourceClipper::applyClippingToContext(RenderObject* target, cons
t FloatRect& targetBoundingBox, | 147 bool RenderSVGResourceClipper::applyClippingToContext(LayoutObject* target, cons
t FloatRect& targetBoundingBox, |
148 const FloatRect& paintInvalidationRect, GraphicsContext* context, ClipperSta
te& clipperState) | 148 const FloatRect& paintInvalidationRect, GraphicsContext* context, ClipperSta
te& clipperState) |
149 { | 149 { |
150 ASSERT(target); | 150 ASSERT(target); |
151 ASSERT(context); | 151 ASSERT(context); |
152 ASSERT(clipperState == ClipperNotApplied); | 152 ASSERT(clipperState == ClipperNotApplied); |
153 ASSERT_WITH_SECURITY_IMPLICATION(!needsLayout()); | 153 ASSERT_WITH_SECURITY_IMPLICATION(!needsLayout()); |
154 | 154 |
155 if (paintInvalidationRect.isEmpty() || m_inClipExpansion) | 155 if (paintInvalidationRect.isEmpty() || m_inClipExpansion) |
156 return false; | 156 return false; |
157 TemporaryChange<bool> inClipExpansionChange(m_inClipExpansion, true); | 157 TemporaryChange<bool> inClipExpansionChange(m_inClipExpansion, true); |
(...skipping 16 matching lines...) Expand all Loading... |
174 // Fall back to masking. | 174 // Fall back to masking. |
175 clipperState = ClipperAppliedMask; | 175 clipperState = ClipperAppliedMask; |
176 | 176 |
177 // Mask layer start | 177 // Mask layer start |
178 context->beginTransparencyLayer(1, &paintInvalidationRect); | 178 context->beginTransparencyLayer(1, &paintInvalidationRect); |
179 { | 179 { |
180 GraphicsContextStateSaver maskContentSaver(*context); | 180 GraphicsContextStateSaver maskContentSaver(*context); |
181 context->concatCTM(animatedLocalTransform); | 181 context->concatCTM(animatedLocalTransform); |
182 | 182 |
183 // clipPath can also be clipped by another clipPath. | 183 // clipPath can also be clipped by another clipPath. |
184 SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObj
ect(this); | 184 SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObj
ect(this); |
185 RenderSVGResourceClipper* clipPathClipper = resources ? resources->clipp
er() : 0; | 185 RenderSVGResourceClipper* clipPathClipper = resources ? resources->clipp
er() : 0; |
186 ClipperState clipPathClipperState = ClipperNotApplied; | 186 ClipperState clipPathClipperState = ClipperNotApplied; |
187 if (clipPathClipper && !clipPathClipper->applyClippingToContext(this, ta
rgetBoundingBox, paintInvalidationRect, context, clipPathClipperState)) { | 187 if (clipPathClipper && !clipPathClipper->applyClippingToContext(this, ta
rgetBoundingBox, paintInvalidationRect, context, clipPathClipperState)) { |
188 // FIXME: Awkward state micro-management. Ideally, GraphicsContextSt
ateSaver should | 188 // FIXME: Awkward state micro-management. Ideally, GraphicsContextSt
ateSaver should |
189 // a) pop saveLayers also | 189 // a) pop saveLayers also |
190 // b) pop multiple states if needed (similarly to SkCanvas::restor
eToCount()) | 190 // b) pop multiple states if needed (similarly to SkCanvas::restor
eToCount()) |
191 // Then we should be able to replace this mess with a single, top-le
vel GCSS. | 191 // Then we should be able to replace this mess with a single, top-le
vel GCSS. |
192 maskContentSaver.restore(); | 192 maskContentSaver.restore(); |
193 context->endLayer(); | 193 context->endLayer(); |
194 return false; | 194 return false; |
195 } | 195 } |
196 | 196 |
197 drawClipMaskContent(context, targetBoundingBox); | 197 drawClipMaskContent(context, targetBoundingBox); |
198 | 198 |
199 if (clipPathClipper) | 199 if (clipPathClipper) |
200 clipPathClipper->postApplyStatefulResource(this, context, clipPathCl
ipperState); | 200 clipPathClipper->postApplyStatefulResource(this, context, clipPathCl
ipperState); |
201 } | 201 } |
202 | 202 |
203 // Masked content layer start. | 203 // Masked content layer start. |
204 context->beginLayer(1, SkXfermode::kSrcIn_Mode, &paintInvalidationRect); | 204 context->beginLayer(1, SkXfermode::kSrcIn_Mode, &paintInvalidationRect); |
205 | 205 |
206 return true; | 206 return true; |
207 } | 207 } |
208 | 208 |
209 void RenderSVGResourceClipper::postApplyStatefulResource(RenderObject* target, G
raphicsContext*& context, ClipperState& clipperState) | 209 void RenderSVGResourceClipper::postApplyStatefulResource(LayoutObject* target, G
raphicsContext*& context, ClipperState& clipperState) |
210 { | 210 { |
211 switch (clipperState) { | 211 switch (clipperState) { |
212 case ClipperAppliedPath: | 212 case ClipperAppliedPath: |
213 // Path-only clipping, no layers to restore but we need to emit an end t
o the clip path display item. | 213 // Path-only clipping, no layers to restore but we need to emit an end t
o the clip path display item. |
214 { | 214 { |
215 if (RuntimeEnabledFeatures::slimmingPaintEnabled()) { | 215 if (RuntimeEnabledFeatures::slimmingPaintEnabled()) { |
216 context->displayItemList()->add(EndClipPathDisplayItem::create(t
arget->displayItemClient())); | 216 context->displayItemList()->add(EndClipPathDisplayItem::create(t
arget->displayItemClient())); |
217 } else { | 217 } else { |
218 EndClipPathDisplayItem endClipPathDisplayItem(target->displayIte
mClient()); | 218 EndClipPathDisplayItem endClipPathDisplayItem(target->displayIte
mClient()); |
219 endClipPathDisplayItem.replay(context); | 219 endClipPathDisplayItem.replay(context); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
255 ASSERT(context); | 255 ASSERT(context); |
256 ASSERT(frame()); | 256 ASSERT(frame()); |
257 | 257 |
258 // Using strokeBoundingBox (instead of paintInvalidationRectInLocalCoordinat
es) to avoid the intersection | 258 // Using strokeBoundingBox (instead of paintInvalidationRectInLocalCoordinat
es) to avoid the intersection |
259 // with local clips/mask, which may yield incorrect results when mixing obje
ctBoundingBox and | 259 // with local clips/mask, which may yield incorrect results when mixing obje
ctBoundingBox and |
260 // userSpaceOnUse units (http://crbug.com/294900). | 260 // userSpaceOnUse units (http://crbug.com/294900). |
261 FloatRect bounds = strokeBoundingBox(); | 261 FloatRect bounds = strokeBoundingBox(); |
262 context->beginRecording(bounds); | 262 context->beginRecording(bounds); |
263 | 263 |
264 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()
); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement
)) { | 264 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()
); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement
)) { |
265 RenderObject* renderer = childElement->renderer(); | 265 LayoutObject* renderer = childElement->renderer(); |
266 if (!renderer) | 266 if (!renderer) |
267 continue; | 267 continue; |
268 | 268 |
269 RenderStyle* style = renderer->style(); | 269 RenderStyle* style = renderer->style(); |
270 if (!style || style->display() == NONE || style->visibility() != VISIBLE
) | 270 if (!style || style->display() == NONE || style->visibility() != VISIBLE
) |
271 continue; | 271 continue; |
272 | 272 |
273 WindRule newClipRule = style->svgStyle().clipRule(); | 273 WindRule newClipRule = style->svgStyle().clipRule(); |
274 bool isUseElement = isSVGUseElement(*childElement); | 274 bool isUseElement = isSVGUseElement(*childElement); |
275 if (isUseElement) { | 275 if (isUseElement) { |
(...skipping 23 matching lines...) Expand all Loading... |
299 renderer->paint(info, IntPoint()); | 299 renderer->paint(info, IntPoint()); |
300 } | 300 } |
301 | 301 |
302 m_clipContentPicture = context->endRecording(); | 302 m_clipContentPicture = context->endRecording(); |
303 } | 303 } |
304 | 304 |
305 void RenderSVGResourceClipper::calculateClipContentPaintInvalidationRect() | 305 void RenderSVGResourceClipper::calculateClipContentPaintInvalidationRect() |
306 { | 306 { |
307 // This is a rough heuristic to appraise the clip size and doesn't consider
clip on clip. | 307 // This is a rough heuristic to appraise the clip size and doesn't consider
clip on clip. |
308 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()
); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement
)) { | 308 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()
); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement
)) { |
309 RenderObject* renderer = childElement->renderer(); | 309 LayoutObject* renderer = childElement->renderer(); |
310 if (!renderer) | 310 if (!renderer) |
311 continue; | 311 continue; |
312 if (!renderer->isSVGShape() && !renderer->isSVGText() && !isSVGUseElemen
t(*childElement)) | 312 if (!renderer->isSVGShape() && !renderer->isSVGText() && !isSVGUseElemen
t(*childElement)) |
313 continue; | 313 continue; |
314 RenderStyle* style = renderer->style(); | 314 RenderStyle* style = renderer->style(); |
315 if (!style || style->display() == NONE || style->visibility() != VISIBLE
) | 315 if (!style || style->display() == NONE || style->visibility() != VISIBLE
) |
316 continue; | 316 continue; |
317 m_clipBoundaries.unite(renderer->localToParentTransform().mapRect(render
er->paintInvalidationRectInLocalCoordinates())); | 317 m_clipBoundaries.unite(renderer->localToParentTransform().mapRect(render
er->paintInvalidationRectInLocalCoordinates())); |
318 } | 318 } |
319 m_clipBoundaries = toSVGClipPathElement(element())->calculateAnimatedLocalTr
ansform().mapRect(m_clipBoundaries); | 319 m_clipBoundaries = toSVGClipPathElement(element())->calculateAnimatedLocalTr
ansform().mapRect(m_clipBoundaries); |
(...skipping 12 matching lines...) Expand all Loading... |
332 point = transform.inverse().mapPoint(point); | 332 point = transform.inverse().mapPoint(point); |
333 } | 333 } |
334 | 334 |
335 AffineTransform animatedLocalTransform = toSVGClipPathElement(element())->ca
lculateAnimatedLocalTransform(); | 335 AffineTransform animatedLocalTransform = toSVGClipPathElement(element())->ca
lculateAnimatedLocalTransform(); |
336 if (!animatedLocalTransform.isInvertible()) | 336 if (!animatedLocalTransform.isInvertible()) |
337 return false; | 337 return false; |
338 | 338 |
339 point = animatedLocalTransform.inverse().mapPoint(point); | 339 point = animatedLocalTransform.inverse().mapPoint(point); |
340 | 340 |
341 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()
); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement
)) { | 341 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()
); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement
)) { |
342 RenderObject* renderer = childElement->renderer(); | 342 LayoutObject* renderer = childElement->renderer(); |
343 if (!renderer) | 343 if (!renderer) |
344 continue; | 344 continue; |
345 if (!renderer->isSVGShape() && !renderer->isSVGText() && !isSVGUseElemen
t(*childElement)) | 345 if (!renderer->isSVGShape() && !renderer->isSVGText() && !isSVGUseElemen
t(*childElement)) |
346 continue; | 346 continue; |
347 IntPoint hitPoint; | 347 IntPoint hitPoint; |
348 HitTestResult result(hitPoint); | 348 HitTestResult result(hitPoint); |
349 if (renderer->nodeAtFloatPoint(HitTestRequest(HitTestRequest::SVGClipCon
tent), result, point, HitTestForeground)) | 349 if (renderer->nodeAtFloatPoint(HitTestRequest(HitTestRequest::SVGClipCon
tent), result, point, HitTestForeground)) |
350 return true; | 350 return true; |
351 } | 351 } |
352 | 352 |
353 return false; | 353 return false; |
354 } | 354 } |
355 | 355 |
356 FloatRect RenderSVGResourceClipper::resourceBoundingBox(const RenderObject* obje
ct) | 356 FloatRect RenderSVGResourceClipper::resourceBoundingBox(const LayoutObject* obje
ct) |
357 { | 357 { |
358 // Resource was not layouted yet. Give back the boundingBox of the object. | 358 // Resource was not layouted yet. Give back the boundingBox of the object. |
359 if (selfNeedsLayout()) | 359 if (selfNeedsLayout()) |
360 return object->objectBoundingBox(); | 360 return object->objectBoundingBox(); |
361 | 361 |
362 if (m_clipBoundaries.isEmpty()) | 362 if (m_clipBoundaries.isEmpty()) |
363 calculateClipContentPaintInvalidationRect(); | 363 calculateClipContentPaintInvalidationRect(); |
364 | 364 |
365 if (clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { | 365 if (clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { |
366 FloatRect objectBoundingBox = object->objectBoundingBox(); | 366 FloatRect objectBoundingBox = object->objectBoundingBox(); |
367 AffineTransform transform; | 367 AffineTransform transform; |
368 transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); | 368 transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); |
369 transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.h
eight()); | 369 transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.h
eight()); |
370 return transform.mapRect(m_clipBoundaries); | 370 return transform.mapRect(m_clipBoundaries); |
371 } | 371 } |
372 | 372 |
373 return m_clipBoundaries; | 373 return m_clipBoundaries; |
374 } | 374 } |
375 | 375 |
376 } | 376 } |
OLD | NEW |