Chromium Code Reviews| 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 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |