Use #pragma once in WebCore
[WebKit-https.git] / Source / WebCore / svg / SVGLocatable.cpp
1 /*
2  * Copyright (C) 2004, 2005 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 2004, 2005, 2006 Rob Buis <buis@kde.org>
4  * Copyright (C) 2009 Google, Inc.  All rights reserved.
5  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #include "config.h"
24 #include "SVGLocatable.h"
25
26 #include "RenderElement.h"
27 #include "SVGException.h"
28 #include "SVGGraphicsElement.h"
29 #include "SVGImageElement.h"
30 #include "SVGNames.h"
31
32 namespace WebCore {
33
34 static bool isViewportElement(Node* node)
35 {
36     return (node->hasTagName(SVGNames::svgTag)
37         || node->hasTagName(SVGNames::symbolTag)
38         || node->hasTagName(SVGNames::foreignObjectTag)
39         || is<SVGImageElement>(*node));
40 }
41
42 SVGElement* SVGLocatable::nearestViewportElement(const SVGElement* element)
43 {
44     ASSERT(element);
45     for (Element* current = element->parentOrShadowHostElement(); current; current = current->parentOrShadowHostElement()) {
46         if (isViewportElement(current))
47             return downcast<SVGElement>(current);
48     }
49
50     return nullptr;
51 }
52
53 SVGElement* SVGLocatable::farthestViewportElement(const SVGElement* element)
54 {
55     ASSERT(element);
56     SVGElement* farthest = nullptr;
57     for (Element* current = element->parentOrShadowHostElement(); current; current = current->parentOrShadowHostElement()) {
58         if (isViewportElement(current))
59             farthest = downcast<SVGElement>(current);
60     }
61     return farthest;
62 }
63
64 FloatRect SVGLocatable::getBBox(SVGElement* element, StyleUpdateStrategy styleUpdateStrategy)
65 {
66     ASSERT(element);
67     if (styleUpdateStrategy == AllowStyleUpdate)
68         element->document().updateLayoutIgnorePendingStylesheets();
69
70     // FIXME: Eventually we should support getBBox for detached elements.
71     if (!element->renderer())
72         return FloatRect();
73
74     return element->renderer()->objectBoundingBox();
75 }
76
77 AffineTransform SVGLocatable::computeCTM(SVGElement* element, CTMScope mode, StyleUpdateStrategy styleUpdateStrategy)
78 {
79     ASSERT(element);
80     if (styleUpdateStrategy == AllowStyleUpdate)
81         element->document().updateLayoutIgnorePendingStylesheets();
82
83     AffineTransform ctm;
84
85     SVGElement* stopAtElement = mode == NearestViewportScope ? nearestViewportElement(element) : nullptr;
86     for (Element* currentElement = element; currentElement; currentElement = currentElement->parentOrShadowHostElement()) {
87         if (!currentElement->isSVGElement())
88             break;
89
90         ctm = downcast<SVGElement>(*currentElement).localCoordinateSpaceTransform(mode).multiply(ctm);
91
92         // For getCTM() computation, stop at the nearest viewport element
93         if (currentElement == stopAtElement)
94             break;
95     }
96
97     return ctm;
98 }
99
100 ExceptionOr<AffineTransform> SVGLocatable::getTransformToElement(SVGElement* target, StyleUpdateStrategy styleUpdateStrategy)
101 {
102     AffineTransform ctm = getCTM(styleUpdateStrategy);
103
104     if (is<SVGGraphicsElement>(target)) {
105         AffineTransform targetCTM = downcast<SVGGraphicsElement>(*target).getCTM(styleUpdateStrategy);
106         if (auto inverse = targetCTM.inverse())
107             ctm = inverse.value() * ctm;
108         else
109             return Exception { SVGException::SVG_MATRIX_NOT_INVERTABLE };
110     }
111
112     return WTFMove(ctm);
113 }
114
115 }