| 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 |