1 /*
2 * Copyright (c) 2009, Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32
33 #include "core/rendering/svg/RenderSVGModelObject.h"
34
35 #include "SVGNames.h"
36 #include "core/rendering/svg/RenderSVGRoot.h"
37 #include "core/rendering/svg/SVGResourcesCache.h"
38 #include "core/svg/SVGGraphicsElement.h"
39
40 namespace WebCore {
41
RenderSVGModelObject(SVGElement * node)42 RenderSVGModelObject::RenderSVGModelObject(SVGElement* node)
43 : RenderObject(node)
44 {
45 }
46
clippedOverflowRectForRepaint(const RenderLayerModelObject * repaintContainer) const47 LayoutRect RenderSVGModelObject::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
48 {
49 return SVGRenderSupport::clippedOverflowRectForRepaint(this, repaintContainer);
50 }
51
computeFloatRectForRepaint(const RenderLayerModelObject * repaintContainer,FloatRect & repaintRect,bool fixed) const52 void RenderSVGModelObject::computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const
53 {
54 SVGRenderSupport::computeFloatRectForRepaint(this, repaintContainer, repaintRect, fixed);
55 }
56
mapLocalToContainer(const RenderLayerModelObject * repaintContainer,TransformState & transformState,MapCoordinatesFlags,bool * wasFixed) const57 void RenderSVGModelObject::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed) const
58 {
59 SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed);
60 }
61
pushMappingToContainer(const RenderLayerModelObject * ancestorToStopAt,RenderGeometryMap & geometryMap) const62 const RenderObject* RenderSVGModelObject::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
63 {
64 return SVGRenderSupport::pushMappingToContainer(this, ancestorToStopAt, geometryMap);
65 }
66
67 // Copied from RenderBox, this method likely requires further refactoring to work easily for both SVG and CSS Box Model content.
68 // FIXME: This may also need to move into SVGRenderSupport as the RenderBox version depends
69 // on borderBoundingBox() which SVG RenderBox subclases (like SVGRenderBlock) do not implement.
outlineBoundsForRepaint(const RenderLayerModelObject * repaintContainer,const RenderGeometryMap *) const70 LayoutRect RenderSVGModelObject::outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap*) const
71 {
72 LayoutRect box = enclosingLayoutRect(repaintRectInLocalCoordinates());
73 adjustRectForOutlineAndShadow(box);
74
75 FloatQuad containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer);
76 return containerRelativeQuad.enclosingBoundingBox();
77 }
78
absoluteRects(Vector<IntRect> & rects,const LayoutPoint & accumulatedOffset) const79 void RenderSVGModelObject::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
80 {
81 IntRect rect = enclosingIntRect(strokeBoundingBox());
82 rect.moveBy(roundedIntPoint(accumulatedOffset));
83 rects.append(rect);
84 }
85
absoluteQuads(Vector<FloatQuad> & quads,bool * wasFixed) const86 void RenderSVGModelObject::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
87 {
88 quads.append(localToAbsoluteQuad(strokeBoundingBox(), 0 /* mode */, wasFixed));
89 }
90
willBeDestroyed()91 void RenderSVGModelObject::willBeDestroyed()
92 {
93 SVGResourcesCache::clientDestroyed(this);
94 RenderObject::willBeDestroyed();
95 }
96
computeLayerHitTestRects(LayerHitTestRects & rects) const97 void RenderSVGModelObject::computeLayerHitTestRects(LayerHitTestRects& rects) const
98 {
99 // Using just the rect for the SVGRoot is good enough for now.
100 SVGRenderSupport::findTreeRootObject(this)->computeLayerHitTestRects(rects);
101 }
102
addLayerHitTestRects(LayerHitTestRects &,const RenderLayer * currentLayer,const LayoutPoint & layerOffset,const LayoutRect & containerRect) const103 void RenderSVGModelObject::addLayerHitTestRects(LayerHitTestRects&, const RenderLayer* currentLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const
104 {
105 // We don't walk into SVG trees at all - just report their container.
106 }
107
styleDidChange(StyleDifference diff,const RenderStyle * oldStyle)108 void RenderSVGModelObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
109 {
110 if (diff == StyleDifferenceLayout) {
111 setNeedsBoundariesUpdate();
112 if (style()->hasTransform())
113 setNeedsTransformUpdate();
114 }
115
116 RenderObject::styleDidChange(diff, oldStyle);
117 SVGResourcesCache::clientStyleChanged(this, diff, style());
118 }
119
nodeAtPoint(const HitTestRequest &,HitTestResult &,const HitTestLocation &,const LayoutPoint &,HitTestAction)120 bool RenderSVGModelObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation&, const LayoutPoint&, HitTestAction)
121 {
122 ASSERT_NOT_REACHED();
123 return false;
124 }
125
getElementCTM(SVGGraphicsElement * element,AffineTransform & transform)126 static void getElementCTM(SVGGraphicsElement* element, AffineTransform& transform)
127 {
128 ASSERT(element);
129 element->document().updateLayoutIgnorePendingStylesheets();
130
131 SVGElement* stopAtElement = element->nearestViewportElement();
132 ASSERT(stopAtElement);
133
134 AffineTransform localTransform;
135 Node* current = element;
136
137 while (current && current->isSVGElement()) {
138 SVGElement* currentElement = toSVGElement(current);
139 localTransform = currentElement->renderer()->localToParentTransform();
140 transform = localTransform.multiply(transform);
141 // For getCTM() computation, stop at the nearest viewport element
142 if (currentElement == stopAtElement)
143 break;
144
145 current = current->parentOrShadowHostNode();
146 }
147 }
148
149 // FloatRect::intersects does not consider horizontal or vertical lines (because of isEmpty()).
150 // So special-case handling of such lines.
intersectsAllowingEmpty(const FloatRect & r,const FloatRect & other)151 static bool intersectsAllowingEmpty(const FloatRect& r, const FloatRect& other)
152 {
153 if (r.isEmpty() && other.isEmpty())
154 return false;
155 if (r.isEmpty() && !other.isEmpty()) {
156 return (other.contains(r.x(), r.y()) && !other.contains(r.maxX(), r.maxY()))
157 || (!other.contains(r.x(), r.y()) && other.contains(r.maxX(), r.maxY()));
158 }
159 if (other.isEmpty() && !r.isEmpty())
160 return intersectsAllowingEmpty(other, r);
161 return r.intersects(other);
162 }
163
164 // One of the element types that can cause graphics to be drawn onto the target canvas. Specifically: circle, ellipse,
165 // image, line, path, polygon, polyline, rect, text and use.
isGraphicsElement(RenderObject * renderer)166 static bool isGraphicsElement(RenderObject* renderer)
167 {
168 return renderer->isSVGShape() || renderer->isSVGText() || renderer->isSVGImage() || renderer->node()->hasTagName(SVGNames::useTag);
169 }
170
171 // The SVG addFocusRingRects() method adds rects in local coordinates so the default absoluteFocusRingQuads
172 // returns incorrect values for SVG objects. Overriding this method provides access to the absolute bounds.
absoluteFocusRingQuads(Vector<FloatQuad> & quads)173 void RenderSVGModelObject::absoluteFocusRingQuads(Vector<FloatQuad>& quads)
174 {
175 quads.append(localToAbsoluteQuad(FloatQuad(repaintRectInLocalCoordinates())));
176 }
177
checkIntersection(RenderObject * renderer,const SVGRect & rect)178 bool RenderSVGModelObject::checkIntersection(RenderObject* renderer, const SVGRect& rect)
179 {
180 if (!renderer || renderer->style()->pointerEvents() == PE_NONE)
181 return false;
182 if (!isGraphicsElement(renderer))
183 return false;
184 AffineTransform ctm;
185 SVGGraphicsElement* svgElement = toSVGGraphicsElement(renderer->node());
186 getElementCTM(svgElement, ctm);
187 ASSERT(svgElement->renderer());
188 return intersectsAllowingEmpty(rect, ctm.mapRect(svgElement->renderer()->repaintRectInLocalCoordinates()));
189 }
190
checkEnclosure(RenderObject * renderer,const SVGRect & rect)191 bool RenderSVGModelObject::checkEnclosure(RenderObject* renderer, const SVGRect& rect)
192 {
193 if (!renderer || renderer->style()->pointerEvents() == PE_NONE)
194 return false;
195 if (!isGraphicsElement(renderer))
196 return false;
197 AffineTransform ctm;
198 SVGGraphicsElement* svgElement = toSVGGraphicsElement(renderer->node());
199 getElementCTM(svgElement, ctm);
200 ASSERT(svgElement->renderer());
201 return rect.contains(ctm.mapRect(svgElement->renderer()->repaintRectInLocalCoordinates()));
202 }
203
204 } // namespace WebCore
205