| 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 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 ASSERT(client); | 56 ASSERT(client); |
| 57 markClientForInvalidation(client, markForInvalidation | 57 markClientForInvalidation(client, markForInvalidation |
| 58 ? BoundariesInvalidation | 58 ? BoundariesInvalidation |
| 59 : ParentOnlyInvalidation); | 59 : ParentOnlyInvalidation); |
| 60 } | 60 } |
| 61 | 61 |
| 62 bool LayoutSVGResourceClipper::calculateClipContentPathIfNeeded() { | 62 bool LayoutSVGResourceClipper::calculateClipContentPathIfNeeded() { |
| 63 if (!m_clipContentPath.isEmpty()) | 63 if (!m_clipContentPath.isEmpty()) |
| 64 return true; | 64 return true; |
| 65 | 65 |
| 66 // If the current clip-path gets clipped itself, we have to fallback to maskin
g. | 66 // If the current clip-path gets clipped itself, we have to fallback to |
| 67 // masking. |
| 67 if (styleRef().clipPath()) | 68 if (styleRef().clipPath()) |
| 68 return false; | 69 return false; |
| 69 | 70 |
| 70 unsigned opCount = 0; | 71 unsigned opCount = 0; |
| 71 bool usingBuilder = false; | 72 bool usingBuilder = false; |
| 72 SkOpBuilder clipPathBuilder; | 73 SkOpBuilder clipPathBuilder; |
| 73 | 74 |
| 74 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); | 75 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); |
| 75 childElement; | 76 childElement; |
| 76 childElement = Traversal<SVGElement>::nextSibling(*childElement)) { | 77 childElement = Traversal<SVGElement>::nextSibling(*childElement)) { |
| 77 LayoutObject* childLayoutObject = childElement->layoutObject(); | 78 LayoutObject* childLayoutObject = childElement->layoutObject(); |
| 78 if (!childLayoutObject) | 79 if (!childLayoutObject) |
| 79 continue; | 80 continue; |
| 80 // Only shapes or paths are supported for direct clipping. We need to fallba
ck to masking for texts. | 81 // Only shapes or paths are supported for direct clipping. We need to |
| 82 // fallback to masking for texts. |
| 81 if (childLayoutObject->isSVGText()) { | 83 if (childLayoutObject->isSVGText()) { |
| 82 m_clipContentPath.clear(); | 84 m_clipContentPath.clear(); |
| 83 return false; | 85 return false; |
| 84 } | 86 } |
| 85 if (!childElement->isSVGGraphicsElement()) | 87 if (!childElement->isSVGGraphicsElement()) |
| 86 continue; | 88 continue; |
| 87 | 89 |
| 88 const ComputedStyle* style = childLayoutObject->style(); | 90 const ComputedStyle* style = childLayoutObject->style(); |
| 89 if (!style || style->display() == EDisplay::None || | 91 if (!style || style->display() == EDisplay::None || |
| 90 (style->visibility() != EVisibility::Visible && | 92 (style->visibility() != EVisibility::Visible && |
| 91 !isSVGUseElement(*childElement))) | 93 !isSVGUseElement(*childElement))) |
| 92 continue; | 94 continue; |
| 93 | 95 |
| 94 // Current shape in clip-path gets clipped too. Fallback to masking. | 96 // Current shape in clip-path gets clipped too. Fallback to masking. |
| 95 if (style->clipPath()) { | 97 if (style->clipPath()) { |
| 96 m_clipContentPath.clear(); | 98 m_clipContentPath.clear(); |
| 97 return false; | 99 return false; |
| 98 } | 100 } |
| 99 | 101 |
| 100 // First clip shape. | 102 // First clip shape. |
| 101 if (m_clipContentPath.isEmpty()) { | 103 if (m_clipContentPath.isEmpty()) { |
| 102 if (isSVGGeometryElement(childElement)) | 104 if (isSVGGeometryElement(childElement)) |
| 103 toSVGGeometryElement(childElement)->toClipPath(m_clipContentPath); | 105 toSVGGeometryElement(childElement)->toClipPath(m_clipContentPath); |
| 104 else if (isSVGUseElement(childElement)) | 106 else if (isSVGUseElement(childElement)) |
| 105 toSVGUseElement(childElement)->toClipPath(m_clipContentPath); | 107 toSVGUseElement(childElement)->toClipPath(m_clipContentPath); |
| 106 | 108 |
| 107 continue; | 109 continue; |
| 108 } | 110 } |
| 109 | 111 |
| 110 // Multiple shapes require PathOps. In some degenerate cases PathOps can exh
ibit quadratic | 112 // Multiple shapes require PathOps. In some degenerate cases PathOps can |
| 111 // behavior, so we cap the number of ops to a reasonable count. | 113 // exhibit quadratic behavior, so we cap the number of ops to a reasonable |
| 114 // count. |
| 112 const unsigned kMaxOps = 42; | 115 const unsigned kMaxOps = 42; |
| 113 if (++opCount > kMaxOps) { | 116 if (++opCount > kMaxOps) { |
| 114 m_clipContentPath.clear(); | 117 m_clipContentPath.clear(); |
| 115 return false; | 118 return false; |
| 116 } | 119 } |
| 117 | 120 |
| 118 // Second clip shape => start using the builder. | 121 // Second clip shape => start using the builder. |
| 119 if (!usingBuilder) { | 122 if (!usingBuilder) { |
| 120 clipPathBuilder.add(m_clipContentPath.getSkPath(), kUnion_SkPathOp); | 123 clipPathBuilder.add(m_clipContentPath.getSkPath(), kUnion_SkPathOp); |
| 121 usingBuilder = true; | 124 usingBuilder = true; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 160 // Transform path by animatedLocalTransform. | 163 // Transform path by animatedLocalTransform. |
| 161 clipPath.transform(animatedLocalTransform); | 164 clipPath.transform(animatedLocalTransform); |
| 162 return true; | 165 return true; |
| 163 } | 166 } |
| 164 | 167 |
| 165 sk_sp<const SkPicture> LayoutSVGResourceClipper::createContentPicture() { | 168 sk_sp<const SkPicture> LayoutSVGResourceClipper::createContentPicture() { |
| 166 ASSERT(frame()); | 169 ASSERT(frame()); |
| 167 if (m_clipContentPicture) | 170 if (m_clipContentPicture) |
| 168 return m_clipContentPicture; | 171 return m_clipContentPicture; |
| 169 | 172 |
| 170 // Using strokeBoundingBox (instead of paintInvalidationRectInLocalSVGCoordina
tes) to avoid the intersection | 173 // Using strokeBoundingBox (instead of |
| 171 // with local clips/mask, which may yield incorrect results when mixing object
BoundingBox and | 174 // paintInvalidationRectInLocalSVGCoordinates) to avoid the intersection with |
| 172 // userSpaceOnUse units (http://crbug.com/294900). | 175 // local clips/mask, which may yield incorrect results when mixing |
| 176 // objectBoundingBox and userSpaceOnUse units (http://crbug.com/294900). |
| 173 FloatRect bounds = strokeBoundingBox(); | 177 FloatRect bounds = strokeBoundingBox(); |
| 174 | 178 |
| 175 SkPictureBuilder pictureBuilder(bounds, nullptr, nullptr); | 179 SkPictureBuilder pictureBuilder(bounds, nullptr, nullptr); |
| 176 | 180 |
| 177 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); | 181 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); |
| 178 childElement; | 182 childElement; |
| 179 childElement = Traversal<SVGElement>::nextSibling(*childElement)) { | 183 childElement = Traversal<SVGElement>::nextSibling(*childElement)) { |
| 180 LayoutObject* layoutObject = childElement->layoutObject(); | 184 LayoutObject* layoutObject = childElement->layoutObject(); |
| 181 if (!layoutObject) | 185 if (!layoutObject) |
| 182 continue; | 186 continue; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 200 continue; | 204 continue; |
| 201 } | 205 } |
| 202 | 206 |
| 203 // Only shapes, paths and texts are allowed for clipping. | 207 // Only shapes, paths and texts are allowed for clipping. |
| 204 if (!layoutObject->isSVGShape() && !layoutObject->isSVGText()) | 208 if (!layoutObject->isSVGShape() && !layoutObject->isSVGText()) |
| 205 continue; | 209 continue; |
| 206 | 210 |
| 207 if (isUseElement) | 211 if (isUseElement) |
| 208 layoutObject = childElement->layoutObject(); | 212 layoutObject = childElement->layoutObject(); |
| 209 | 213 |
| 210 // Switch to a paint behavior where all children of this <clipPath> will be
laid out using special constraints: | 214 // Switch to a paint behavior where all children of this <clipPath> will be |
| 215 // laid out using special constraints: |
| 211 // - fill-opacity/stroke-opacity/opacity set to 1 | 216 // - fill-opacity/stroke-opacity/opacity set to 1 |
| 212 // - masker/filter not applied when laying out the children | 217 // - masker/filter not applied when laying out the children |
| 213 // - fill is set to the initial fill paint server (solid, black) | 218 // - fill is set to the initial fill paint server (solid, black) |
| 214 // - stroke is set to the initial stroke paint server (none) | 219 // - stroke is set to the initial stroke paint server (none) |
| 215 PaintInfo info(pictureBuilder.context(), LayoutRect::infiniteIntRect(), | 220 PaintInfo info(pictureBuilder.context(), LayoutRect::infiniteIntRect(), |
| 216 PaintPhaseForeground, GlobalPaintNormalPhase, | 221 PaintPhaseForeground, GlobalPaintNormalPhase, |
| 217 PaintLayerPaintingRenderingClipPathAsMask); | 222 PaintLayerPaintingRenderingClipPathAsMask); |
| 218 layoutObject->paint(info, IntPoint()); | 223 layoutObject->paint(info, IntPoint()); |
| 219 } | 224 } |
| 220 | 225 |
| 221 m_clipContentPicture = pictureBuilder.endRecording(); | 226 m_clipContentPicture = pictureBuilder.endRecording(); |
| 222 return m_clipContentPicture; | 227 return m_clipContentPicture; |
| 223 } | 228 } |
| 224 | 229 |
| 225 void LayoutSVGResourceClipper::calculateLocalClipBounds() { | 230 void LayoutSVGResourceClipper::calculateLocalClipBounds() { |
| 226 // This is a rough heuristic to appraise the clip size and doesn't consider cl
ip on clip. | 231 // This is a rough heuristic to appraise the clip size and doesn't consider |
| 232 // clip on clip. |
| 227 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); | 233 for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); |
| 228 childElement; | 234 childElement; |
| 229 childElement = Traversal<SVGElement>::nextSibling(*childElement)) { | 235 childElement = Traversal<SVGElement>::nextSibling(*childElement)) { |
| 230 LayoutObject* layoutObject = childElement->layoutObject(); | 236 LayoutObject* layoutObject = childElement->layoutObject(); |
| 231 if (!layoutObject) | 237 if (!layoutObject) |
| 232 continue; | 238 continue; |
| 233 if (!layoutObject->isSVGShape() && !layoutObject->isSVGText() && | 239 if (!layoutObject->isSVGShape() && !layoutObject->isSVGText() && |
| 234 !isSVGUseElement(*childElement)) | 240 !isSVGUseElement(*childElement)) |
| 235 continue; | 241 continue; |
| 236 const ComputedStyle* style = layoutObject->style(); | 242 const ComputedStyle* style = layoutObject->style(); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 300 AffineTransform transform = | 306 AffineTransform transform = |
| 301 toSVGClipPathElement(element())->calculateAnimatedLocalTransform(); | 307 toSVGClipPathElement(element())->calculateAnimatedLocalTransform(); |
| 302 if (clipPathUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) { | 308 if (clipPathUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) { |
| 303 transform.translate(referenceBox.x(), referenceBox.y()); | 309 transform.translate(referenceBox.x(), referenceBox.y()); |
| 304 transform.scaleNonUniform(referenceBox.width(), referenceBox.height()); | 310 transform.scaleNonUniform(referenceBox.width(), referenceBox.height()); |
| 305 } | 311 } |
| 306 return transform.mapRect(m_localClipBounds); | 312 return transform.mapRect(m_localClipBounds); |
| 307 } | 313 } |
| 308 | 314 |
| 309 } // namespace blink | 315 } // namespace blink |
| OLD | NEW |