• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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