| 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 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 #include "SVGUnitTypes.h" | 47 #include "SVGUnitTypes.h" |
| 48 #include "SVGUseElement.h" | 48 #include "SVGUseElement.h" |
| 49 #include <wtf/UnusedParam.h> | 49 #include <wtf/UnusedParam.h> |
| 50 | 50 |
| 51 namespace WebCore { | 51 namespace WebCore { |
| 52 | 52 |
| 53 RenderSVGResourceType RenderSVGResourceClipper::s_resourceType = ClipperResource
Type; | 53 RenderSVGResourceType RenderSVGResourceClipper::s_resourceType = ClipperResource
Type; |
| 54 | 54 |
| 55 RenderSVGResourceClipper::RenderSVGResourceClipper(SVGClipPathElement* node) | 55 RenderSVGResourceClipper::RenderSVGResourceClipper(SVGClipPathElement* node) |
| 56 : RenderSVGResourceContainer(node) | 56 : RenderSVGResourceContainer(node) |
| 57 , m_invalidationBlocked(false) | |
| 58 { | 57 { |
| 59 } | 58 } |
| 60 | 59 |
| 61 RenderSVGResourceClipper::~RenderSVGResourceClipper() | 60 RenderSVGResourceClipper::~RenderSVGResourceClipper() |
| 62 { | 61 { |
| 63 if (m_clipper.isEmpty()) | 62 if (m_clipper.isEmpty()) |
| 64 return; | 63 return; |
| 65 | 64 |
| 66 deleteAllValues(m_clipper); | 65 deleteAllValues(m_clipper); |
| 67 m_clipper.clear(); | 66 m_clipper.clear(); |
| 68 } | 67 } |
| 69 | 68 |
| 70 void RenderSVGResourceClipper::removeAllClientsFromCache(bool markForInvalidatio
n) | 69 void RenderSVGResourceClipper::removeAllClientsFromCache(bool markForInvalidatio
n) |
| 71 { | 70 { |
| 72 if (m_invalidationBlocked) | |
| 73 return; | |
| 74 | |
| 75 m_clipBoundaries = FloatRect(); | 71 m_clipBoundaries = FloatRect(); |
| 76 if (!m_clipper.isEmpty()) { | 72 if (!m_clipper.isEmpty()) { |
| 77 deleteAllValues(m_clipper); | 73 deleteAllValues(m_clipper); |
| 78 m_clipper.clear(); | 74 m_clipper.clear(); |
| 79 } | 75 } |
| 80 | 76 |
| 81 markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInval
idation : ParentOnlyInvalidation); | 77 markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInval
idation : ParentOnlyInvalidation); |
| 82 } | 78 } |
| 83 | 79 |
| 84 void RenderSVGResourceClipper::removeClientFromCache(RenderObject* client, bool
markForInvalidation) | 80 void RenderSVGResourceClipper::removeClientFromCache(RenderObject* client, bool
markForInvalidation) |
| 85 { | 81 { |
| 86 ASSERT(client); | 82 ASSERT(client); |
| 87 if (m_invalidationBlocked) | |
| 88 return; | |
| 89 | |
| 90 if (m_clipper.contains(client)) | 83 if (m_clipper.contains(client)) |
| 91 delete m_clipper.take(client); | 84 delete m_clipper.take(client); |
| 92 | 85 |
| 93 markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidati
on : ParentOnlyInvalidation); | 86 markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidati
on : ParentOnlyInvalidation); |
| 94 } | 87 } |
| 95 | 88 |
| 96 bool RenderSVGResourceClipper::applyResource(RenderObject* object, RenderStyle*,
GraphicsContext*& context, unsigned short resourceMode) | 89 bool RenderSVGResourceClipper::applyResource(RenderObject* object, RenderStyle*,
GraphicsContext*& context, unsigned short resourceMode) |
| 97 { | 90 { |
| 98 ASSERT(object); | 91 ASSERT(object); |
| 99 ASSERT(context); | 92 ASSERT(context); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 maskContext->concatCTM(absoluteTransform); | 185 maskContext->concatCTM(absoluteTransform); |
| 193 | 186 |
| 194 // clipPath can also be clipped by another clipPath. | 187 // clipPath can also be clipped by another clipPath. |
| 195 if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRende
rObject(this)) { | 188 if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRende
rObject(this)) { |
| 196 if (RenderSVGResourceClipper* clipper = resources->clipper()) { | 189 if (RenderSVGResourceClipper* clipper = resources->clipper()) { |
| 197 if (!clipper->applyClippingToContext(this, objectBoundingBox, re
paintRect, maskContext)) | 190 if (!clipper->applyClippingToContext(this, objectBoundingBox, re
paintRect, maskContext)) |
| 198 return false; | 191 return false; |
| 199 } | 192 } |
| 200 } | 193 } |
| 201 | 194 |
| 202 drawContentIntoMaskImage(clipperData, objectBoundingBox); | 195 if (!drawContentIntoMaskImage(clipperData, objectBoundingBox)) { |
| 196 stateSaver.restore(); |
| 197 clipperData->clipMaskImage.clear(); |
| 198 } |
| 203 } | 199 } |
| 204 | 200 |
| 205 if (!clipperData->clipMaskImage) | 201 if (!clipperData->clipMaskImage) |
| 206 return false; | 202 return false; |
| 207 | 203 |
| 208 SVGImageBufferTools::clipToImageBuffer(context, absoluteTransform, clampedAb
soluteTargetRect, clipperData->clipMaskImage); | 204 SVGImageBufferTools::clipToImageBuffer(context, absoluteTransform, clampedAb
soluteTargetRect, clipperData->clipMaskImage); |
| 209 return true; | 205 return true; |
| 210 } | 206 } |
| 211 | 207 |
| 212 bool RenderSVGResourceClipper::drawContentIntoMaskImage(ClipperData* clipperData
, const FloatRect& objectBoundingBox) | 208 bool RenderSVGResourceClipper::drawContentIntoMaskImage(ClipperData* clipperData
, const FloatRect& objectBoundingBox) |
| 213 { | 209 { |
| 210 ASSERT(frame()); |
| 214 ASSERT(clipperData); | 211 ASSERT(clipperData); |
| 215 ASSERT(clipperData->clipMaskImage); | 212 ASSERT(clipperData->clipMaskImage); |
| 216 | 213 |
| 217 GraphicsContext* maskContext = clipperData->clipMaskImage->context(); | 214 GraphicsContext* maskContext = clipperData->clipMaskImage->context(); |
| 218 ASSERT(maskContext); | 215 ASSERT(maskContext); |
| 219 | 216 |
| 220 AffineTransform maskContentTransformation; | 217 AffineTransform maskContentTransformation; |
| 221 SVGClipPathElement* clipPath = static_cast<SVGClipPathElement*>(node()); | 218 SVGClipPathElement* clipPath = static_cast<SVGClipPathElement*>(node()); |
| 222 if (clipPath->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGB
OX) { | 219 if (clipPath->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGB
OX) { |
| 223 maskContentTransformation.translate(objectBoundingBox.x(), objectBoundin
gBox.y()); | 220 maskContentTransformation.translate(objectBoundingBox.x(), objectBoundin
gBox.y()); |
| 224 maskContentTransformation.scaleNonUniform(objectBoundingBox.width(), obj
ectBoundingBox.height()); | 221 maskContentTransformation.scaleNonUniform(objectBoundingBox.width(), obj
ectBoundingBox.height()); |
| 225 maskContext->concatCTM(maskContentTransformation); | 222 maskContext->concatCTM(maskContentTransformation); |
| 226 } | 223 } |
| 227 | 224 |
| 225 // Switch to a paint behavior where all children of this <clipPath> will be
rendered using special constraints: |
| 226 // - fill-opacity/stroke-opacity/opacity set to 1 |
| 227 // - masker/filter not applied when rendering the children |
| 228 // - fill is set to the initial fill paint server (solid, black) |
| 229 // - stroke is set to the initial stroke paint server (none) |
| 230 PaintBehavior oldBehavior = frame()->view()->paintBehavior(); |
| 231 frame()->view()->setPaintBehavior(oldBehavior | PaintBehaviorRenderingSVGMas
k); |
| 232 |
| 228 // Draw all clipPath children into a global mask. | 233 // Draw all clipPath children into a global mask. |
| 229 for (Node* childNode = node()->firstChild(); childNode; childNode = childNod
e->nextSibling()) { | 234 for (Node* childNode = node()->firstChild(); childNode; childNode = childNod
e->nextSibling()) { |
| 230 RenderObject* renderer = childNode->renderer(); | 235 RenderObject* renderer = childNode->renderer(); |
| 231 if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->
isStyled() || !renderer) | 236 if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->
isStyled() || !renderer) |
| 232 continue; | 237 continue; |
| 238 if (renderer->needsLayout()) { |
| 239 frame()->view()->setPaintBehavior(oldBehavior); |
| 240 return false; |
| 241 } |
| 233 RenderStyle* style = renderer->style(); | 242 RenderStyle* style = renderer->style(); |
| 234 if (!style || style->display() == NONE || style->visibility() != VISIBLE
) | 243 if (!style || style->display() == NONE || style->visibility() != VISIBLE
) |
| 235 continue; | 244 continue; |
| 236 | 245 |
| 237 WindRule newClipRule = style->svgStyle()->clipRule(); | 246 WindRule newClipRule = style->svgStyle()->clipRule(); |
| 238 bool isUseElement = renderer->isSVGShadowTreeRootContainer(); | 247 bool isUseElement = renderer->isSVGShadowTreeRootContainer(); |
| 239 if (isUseElement) { | 248 if (isUseElement) { |
| 240 SVGUseElement* useElement = static_cast<SVGUseElement*>(childNode); | 249 SVGUseElement* useElement = static_cast<SVGUseElement*>(childNode); |
| 241 renderer = useElement->rendererClipChild(); | 250 renderer = useElement->rendererClipChild(); |
| 242 if (!renderer) | 251 if (!renderer) |
| 243 continue; | 252 continue; |
| 244 if (!useElement->hasAttribute(SVGNames::clip_ruleAttr)) | 253 if (!useElement->hasAttribute(SVGNames::clip_ruleAttr)) |
| 245 newClipRule = renderer->style()->svgStyle()->clipRule(); | 254 newClipRule = renderer->style()->svgStyle()->clipRule(); |
| 246 } | 255 } |
| 247 | 256 |
| 248 // Only shapes, paths and texts are allowed for clipping. | 257 // Only shapes, paths and texts are allowed for clipping. |
| 249 if (!renderer->isSVGShape() && !renderer->isSVGText()) | 258 if (!renderer->isSVGShape() && !renderer->isSVGText()) |
| 250 continue; | 259 continue; |
| 251 | 260 |
| 252 // Save the old RenderStyle of the current object for restoring after dr
awing | 261 maskContext->setFillRule(newClipRule); |
| 253 // it to the MaskImage. The new intermediate RenderStyle needs to inheri
t from | |
| 254 // the old one. | |
| 255 RefPtr<RenderStyle> oldRenderStyle = renderer->style(); | |
| 256 RefPtr<RenderStyle> newRenderStyle = RenderStyle::clone(oldRenderStyle.g
et()); | |
| 257 SVGRenderStyle* svgStyle = newRenderStyle.get()->accessSVGStyle(); | |
| 258 svgStyle->setFillPaint(SVGRenderStyle::initialFillPaintType(), SVGRender
Style::initialFillPaintColor(), SVGRenderStyle::initialFillPaintUri()); | |
| 259 svgStyle->setStrokePaint(SVGRenderStyle::initialStrokePaintType(), SVGRe
nderStyle::initialStrokePaintColor(), SVGRenderStyle::initialStrokePaintUri()); | |
| 260 svgStyle->setFillRule(newClipRule); | |
| 261 newRenderStyle.get()->setOpacity(1); | |
| 262 svgStyle->setFillOpacity(1); | |
| 263 svgStyle->setStrokeOpacity(1); | |
| 264 svgStyle->setFilterResource(String()); | |
| 265 svgStyle->setMaskerResource(String()); | |
| 266 | |
| 267 // The setStyle() call results in a styleDidChange() call, which in turn
invalidations the resources. | |
| 268 // As we're mutating the resource on purpose, block updates until we've
resetted the style again. | |
| 269 m_invalidationBlocked = true; | |
| 270 renderer->setStyle(newRenderStyle.release()); | |
| 271 | 262 |
| 272 // In the case of a <use> element, we obtained its renderere above, to r
etrieve its clipRule. | 263 // In the case of a <use> element, we obtained its renderere above, to r
etrieve its clipRule. |
| 273 // We have to pass the <use> renderer itself to renderSubtreeToImageBuff
er() to apply it's x/y/transform/etc. values when rendering. | 264 // We have to pass the <use> renderer itself to renderSubtreeToImageBuff
er() to apply it's x/y/transform/etc. values when rendering. |
| 274 // So if isUseElement is true, refetch the childNode->renderer(), as ren
derer got overriden above. | 265 // So if isUseElement is true, refetch the childNode->renderer(), as ren
derer got overriden above. |
| 275 SVGImageBufferTools::renderSubtreeToImageBuffer(clipperData->clipMaskIma
ge.get(), isUseElement ? childNode->renderer() : renderer, maskContentTransforma
tion); | 266 SVGImageBufferTools::renderSubtreeToImageBuffer(clipperData->clipMaskIma
ge.get(), isUseElement ? childNode->renderer() : renderer, maskContentTransforma
tion); |
| 276 | |
| 277 renderer->setStyle(oldRenderStyle.release()); | |
| 278 m_invalidationBlocked = false; | |
| 279 } | 267 } |
| 280 | 268 |
| 269 frame()->view()->setPaintBehavior(oldBehavior); |
| 281 return true; | 270 return true; |
| 282 } | 271 } |
| 283 | 272 |
| 284 void RenderSVGResourceClipper::calculateClipContentRepaintRect() | 273 void RenderSVGResourceClipper::calculateClipContentRepaintRect() |
| 285 { | 274 { |
| 286 // This is a rough heuristic to appraise the clip size and doesn't consider
clip on clip. | 275 // This is a rough heuristic to appraise the clip size and doesn't consider
clip on clip. |
| 287 for (Node* childNode = node()->firstChild(); childNode; childNode = childNod
e->nextSibling()) { | 276 for (Node* childNode = node()->firstChild(); childNode; childNode = childNod
e->nextSibling()) { |
| 288 RenderObject* renderer = childNode->renderer(); | 277 RenderObject* renderer = childNode->renderer(); |
| 289 if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->
isStyled() || !renderer) | 278 if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->
isStyled() || !renderer) |
| 290 continue; | 279 continue; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 345 transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.h
eight()); | 334 transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.h
eight()); |
| 346 return transform.mapRect(m_clipBoundaries); | 335 return transform.mapRect(m_clipBoundaries); |
| 347 } | 336 } |
| 348 | 337 |
| 349 return m_clipBoundaries; | 338 return m_clipBoundaries; |
| 350 } | 339 } |
| 351 | 340 |
| 352 } | 341 } |
| 353 | 342 |
| 354 #endif // ENABLE(SVG) | 343 #endif // ENABLE(SVG) |
| OLD | NEW |