1 | /* |
2 | * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann@kde.org> |
3 | * Copyright (C) 2004, 2005, 2006, 2007, 2010 Rob Buis <buis@kde.org> |
4 | * Copyright (C) 2018 Apple Inc. All rights reserved. |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Library General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the License, or (at your option) any later version. |
10 | * |
11 | * This library is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Library General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Library General Public License |
17 | * along with this library; see the file COPYING.LIB. If not, write to |
18 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
19 | * Boston, MA 02110-1301, USA. |
20 | */ |
21 | |
22 | #include "config.h" |
23 | #include "SVGFitToViewBox.h" |
24 | |
25 | #include "AffineTransform.h" |
26 | #include "Document.h" |
27 | #include "FloatRect.h" |
28 | #include "SVGDocumentExtensions.h" |
29 | #include "SVGElement.h" |
30 | #include "SVGNames.h" |
31 | #include "SVGParserUtilities.h" |
32 | #include "SVGPreserveAspectRatioValue.h" |
33 | #include <wtf/text/StringView.h> |
34 | |
35 | namespace WebCore { |
36 | |
37 | SVGFitToViewBox::SVGFitToViewBox(SVGElement* contextElement, SVGPropertyAccess access) |
38 | : m_viewBox(SVGAnimatedRect::create(contextElement, access)) |
39 | , m_preserveAspectRatio(SVGAnimatedPreserveAspectRatio::create(contextElement, access)) |
40 | { |
41 | static std::once_flag onceFlag; |
42 | std::call_once(onceFlag, [] { |
43 | PropertyRegistry::registerProperty<SVGNames::viewBoxAttr, &SVGFitToViewBox::m_viewBox>(); |
44 | PropertyRegistry::registerProperty<SVGNames::preserveAspectRatioAttr, &SVGFitToViewBox::m_preserveAspectRatio>(); |
45 | }); |
46 | } |
47 | |
48 | void SVGFitToViewBox::setViewBox(const FloatRect& viewBox) |
49 | { |
50 | m_viewBox->setBaseValInternal(viewBox); |
51 | m_isViewBoxValid = true; |
52 | } |
53 | |
54 | void SVGFitToViewBox::resetViewBox() |
55 | { |
56 | m_viewBox->setBaseValInternal({ }); |
57 | m_isViewBoxValid = false; |
58 | } |
59 | |
60 | void SVGFitToViewBox::reset() |
61 | { |
62 | resetViewBox(); |
63 | resetPreserveAspectRatio(); |
64 | } |
65 | |
66 | bool SVGFitToViewBox::parseAttribute(const QualifiedName& name, const AtomicString& value) |
67 | { |
68 | if (name == SVGNames::viewBoxAttr) { |
69 | FloatRect viewBox; |
70 | if (!value.isNull() && parseViewBox(value, viewBox)) |
71 | setViewBox(viewBox); |
72 | else |
73 | resetViewBox(); |
74 | return true; |
75 | } |
76 | |
77 | if (name == SVGNames::preserveAspectRatioAttr) { |
78 | SVGPreserveAspectRatioValue preserveAspectRatio; |
79 | preserveAspectRatio.parse(value); |
80 | setPreserveAspectRatio(preserveAspectRatio); |
81 | return true; |
82 | } |
83 | |
84 | return false; |
85 | } |
86 | |
87 | bool SVGFitToViewBox::parseViewBox(const AtomicString& value, FloatRect& viewBox) |
88 | { |
89 | auto upconvertedCharacters = StringView(value).upconvertedCharacters(); |
90 | const UChar* characters = upconvertedCharacters; |
91 | return parseViewBox(characters, characters + value.length(), viewBox); |
92 | } |
93 | |
94 | bool SVGFitToViewBox::parseViewBox(const UChar*& c, const UChar* end, FloatRect& viewBox, bool validate) |
95 | { |
96 | String str(c, end - c); |
97 | |
98 | skipOptionalSVGSpaces(c, end); |
99 | |
100 | float x = 0.0f; |
101 | float y = 0.0f; |
102 | float width = 0.0f; |
103 | float height = 0.0f; |
104 | bool valid = parseNumber(c, end, x) && parseNumber(c, end, y) && parseNumber(c, end, width) && parseNumber(c, end, height, false); |
105 | |
106 | if (validate) { |
107 | Document& document = m_viewBox->contextElement()->document(); |
108 | |
109 | if (!valid) { |
110 | document.accessSVGExtensions().reportWarning("Problem parsing viewBox=\"" + str + "\"" ); |
111 | return false; |
112 | } |
113 | |
114 | // Check that width is positive. |
115 | if (width < 0.0) { |
116 | document.accessSVGExtensions().reportError("A negative value for ViewBox width is not allowed" ); |
117 | return false; |
118 | } |
119 | |
120 | // Check that height is positive. |
121 | if (height < 0.0) { |
122 | document.accessSVGExtensions().reportError("A negative value for ViewBox height is not allowed" ); |
123 | return false; |
124 | } |
125 | |
126 | // Nothing should come after the last, fourth number. |
127 | skipOptionalSVGSpaces(c, end); |
128 | if (c < end) { |
129 | document.accessSVGExtensions().reportWarning("Problem parsing viewBox=\"" + str + "\"" ); |
130 | return false; |
131 | } |
132 | } |
133 | |
134 | viewBox = { x, y, width, height }; |
135 | return true; |
136 | } |
137 | |
138 | AffineTransform SVGFitToViewBox::viewBoxToViewTransform(const FloatRect& viewBoxRect, const SVGPreserveAspectRatioValue& preserveAspectRatio, float viewWidth, float viewHeight) |
139 | { |
140 | if (!viewBoxRect.width() || !viewBoxRect.height() || !viewWidth || !viewHeight) |
141 | return AffineTransform(); |
142 | |
143 | return preserveAspectRatio.getCTM(viewBoxRect.x(), viewBoxRect.y(), viewBoxRect.width(), viewBoxRect.height(), viewWidth, viewHeight); |
144 | } |
145 | |
146 | } |
147 | |