Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / svg / SVGPreserveAspectRatio.cpp
blob063f20c325f275817a7cb2ee7a8b78e6b49198aa
1 /*
2 * Copyright (C) 2004, 2005, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4 * Copyright (C) 2010 Dirk Schulze <krit@webkit.org>
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.
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.
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.
22 #include "config.h"
23 #include "core/svg/SVGPreserveAspectRatio.h"
25 #include "bindings/core/v8/ExceptionState.h"
26 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
27 #include "core/dom/ExceptionCode.h"
28 #include "core/svg/SVGAnimationElement.h"
29 #include "core/svg/SVGParserUtilities.h"
30 #include "platform/geometry/FloatRect.h"
31 #include "platform/transforms/AffineTransform.h"
32 #include "wtf/text/WTFString.h"
34 namespace blink {
36 SVGPreserveAspectRatio::SVGPreserveAspectRatio()
38 setDefault();
41 void SVGPreserveAspectRatio::setDefault()
43 m_align = SVG_PRESERVEASPECTRATIO_XMIDYMID;
44 m_meetOrSlice = SVG_MEETORSLICE_MEET;
47 PassRefPtrWillBeRawPtr<SVGPreserveAspectRatio> SVGPreserveAspectRatio::clone() const
49 RefPtrWillBeRawPtr<SVGPreserveAspectRatio> preserveAspectRatio = create();
51 preserveAspectRatio->m_align = m_align;
52 preserveAspectRatio->m_meetOrSlice = m_meetOrSlice;
54 return preserveAspectRatio.release();
57 template<typename CharType>
58 bool SVGPreserveAspectRatio::parseInternal(const CharType*& ptr, const CharType* end, bool validate)
60 SVGPreserveAspectRatioType align = SVG_PRESERVEASPECTRATIO_XMIDYMID;
61 SVGMeetOrSliceType meetOrSlice = SVG_MEETORSLICE_MEET;
63 setAlign(align);
64 setMeetOrSlice(meetOrSlice);
66 if (!skipOptionalSVGSpaces(ptr, end))
67 return false;
69 if (*ptr == 'n') {
70 if (!skipString(ptr, end, "none"))
71 return false;
72 align = SVG_PRESERVEASPECTRATIO_NONE;
73 skipOptionalSVGSpaces(ptr, end);
74 } else if (*ptr == 'x') {
75 if ((end - ptr) < 8)
76 return false;
77 if (ptr[1] != 'M' || ptr[4] != 'Y' || ptr[5] != 'M')
78 return false;
79 if (ptr[2] == 'i') {
80 if (ptr[3] == 'n') {
81 if (ptr[6] == 'i') {
82 if (ptr[7] == 'n')
83 align = SVG_PRESERVEASPECTRATIO_XMINYMIN;
84 else if (ptr[7] == 'd')
85 align = SVG_PRESERVEASPECTRATIO_XMINYMID;
86 else
87 return false;
88 } else if (ptr[6] == 'a' && ptr[7] == 'x') {
89 align = SVG_PRESERVEASPECTRATIO_XMINYMAX;
90 } else {
91 return false;
93 } else if (ptr[3] == 'd') {
94 if (ptr[6] == 'i') {
95 if (ptr[7] == 'n')
96 align = SVG_PRESERVEASPECTRATIO_XMIDYMIN;
97 else if (ptr[7] == 'd')
98 align = SVG_PRESERVEASPECTRATIO_XMIDYMID;
99 else
100 return false;
101 } else if (ptr[6] == 'a' && ptr[7] == 'x') {
102 align = SVG_PRESERVEASPECTRATIO_XMIDYMAX;
103 } else {
104 return false;
106 } else {
107 return false;
109 } else if (ptr[2] == 'a' && ptr[3] == 'x') {
110 if (ptr[6] == 'i') {
111 if (ptr[7] == 'n')
112 align = SVG_PRESERVEASPECTRATIO_XMAXYMIN;
113 else if (ptr[7] == 'd')
114 align = SVG_PRESERVEASPECTRATIO_XMAXYMID;
115 else
116 return false;
117 } else if (ptr[6] == 'a' && ptr[7] == 'x') {
118 align = SVG_PRESERVEASPECTRATIO_XMAXYMAX;
119 } else {
120 return false;
122 } else {
123 return false;
125 ptr += 8;
126 skipOptionalSVGSpaces(ptr, end);
127 } else {
128 return false;
131 if (ptr < end) {
132 if (*ptr == 'm') {
133 if (!skipString(ptr, end, "meet"))
134 return false;
135 skipOptionalSVGSpaces(ptr, end);
136 } else if (*ptr == 's') {
137 if (!skipString(ptr, end, "slice"))
138 return false;
139 skipOptionalSVGSpaces(ptr, end);
140 if (align != SVG_PRESERVEASPECTRATIO_NONE)
141 meetOrSlice = SVG_MEETORSLICE_SLICE;
145 if (end != ptr && validate)
146 return false;
148 setAlign(align);
149 setMeetOrSlice(meetOrSlice);
151 return true;
154 void SVGPreserveAspectRatio::setValueAsString(const String& string, ExceptionState& exceptionState)
156 setDefault();
158 if (string.isEmpty())
159 return;
161 bool valid = false;
162 if (string.is8Bit()) {
163 const LChar* ptr = string.characters8();
164 const LChar* end = ptr + string.length();
165 valid = parseInternal(ptr, end, true);
166 } else {
167 const UChar* ptr = string.characters16();
168 const UChar* end = ptr + string.length();
169 valid = parseInternal(ptr, end, true);
172 if (!valid) {
173 exceptionState.throwDOMException(SyntaxError, "The value provided ('" + string + "') is invalid.");
177 bool SVGPreserveAspectRatio::parse(const LChar*& ptr, const LChar* end, bool validate)
179 return parseInternal(ptr, end, validate);
182 bool SVGPreserveAspectRatio::parse(const UChar*& ptr, const UChar* end, bool validate)
184 return parseInternal(ptr, end, validate);
187 void SVGPreserveAspectRatio::transformRect(FloatRect& destRect, FloatRect& srcRect)
189 if (m_align == SVG_PRESERVEASPECTRATIO_NONE)
190 return;
192 FloatSize imageSize = srcRect.size();
193 float origDestWidth = destRect.width();
194 float origDestHeight = destRect.height();
195 switch (m_meetOrSlice) {
196 case SVGPreserveAspectRatio::SVG_MEETORSLICE_UNKNOWN:
197 break;
198 case SVGPreserveAspectRatio::SVG_MEETORSLICE_MEET: {
199 float widthToHeightMultiplier = srcRect.height() / srcRect.width();
200 if (origDestHeight > origDestWidth * widthToHeightMultiplier) {
201 destRect.setHeight(origDestWidth * widthToHeightMultiplier);
202 switch (m_align) {
203 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID:
204 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
205 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
206 destRect.setY(destRect.y() + origDestHeight / 2 - destRect.height() / 2);
207 break;
208 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX:
209 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
210 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
211 destRect.setY(destRect.y() + origDestHeight - destRect.height());
212 break;
213 default:
214 break;
217 if (origDestWidth > origDestHeight / widthToHeightMultiplier) {
218 destRect.setWidth(origDestHeight / widthToHeightMultiplier);
219 switch (m_align) {
220 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN:
221 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
222 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
223 destRect.setX(destRect.x() + origDestWidth / 2 - destRect.width() / 2);
224 break;
225 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN:
226 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
227 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
228 destRect.setX(destRect.x() + origDestWidth - destRect.width());
229 break;
230 default:
231 break;
234 break;
236 case SVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE: {
237 float widthToHeightMultiplier = srcRect.height() / srcRect.width();
238 // if the destination height is less than the height of the image we'll be drawing
239 if (origDestHeight < origDestWidth * widthToHeightMultiplier) {
240 float destToSrcMultiplier = srcRect.width() / destRect.width();
241 srcRect.setHeight(destRect.height() * destToSrcMultiplier);
242 switch (m_align) {
243 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID:
244 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
245 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
246 srcRect.setY(srcRect.y() + imageSize.height() / 2 - srcRect.height() / 2);
247 break;
248 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX:
249 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
250 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
251 srcRect.setY(srcRect.y() + imageSize.height() - srcRect.height());
252 break;
253 default:
254 break;
257 // if the destination width is less than the width of the image we'll be drawing
258 if (origDestWidth < origDestHeight / widthToHeightMultiplier) {
259 float destToSrcMultiplier = srcRect.height() / destRect.height();
260 srcRect.setWidth(destRect.width() * destToSrcMultiplier);
261 switch (m_align) {
262 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN:
263 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
264 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
265 srcRect.setX(srcRect.x() + imageSize.width() / 2 - srcRect.width() / 2);
266 break;
267 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN:
268 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
269 case SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
270 srcRect.setX(srcRect.x() + imageSize.width() - srcRect.width());
271 break;
272 default:
273 break;
276 break;
281 AffineTransform SVGPreserveAspectRatio::getCTM(float logicalX, float logicalY, float logicalWidth, float logicalHeight, float physicalWidth, float physicalHeight) const
283 ASSERT(logicalWidth);
284 ASSERT(logicalHeight);
285 ASSERT(physicalWidth);
286 ASSERT(physicalHeight);
288 AffineTransform transform;
289 if (m_align == SVG_PRESERVEASPECTRATIO_UNKNOWN)
290 return transform;
292 double extendedLogicalX = logicalX;
293 double extendedLogicalY = logicalY;
294 double extendedLogicalWidth = logicalWidth;
295 double extendedLogicalHeight = logicalHeight;
296 double extendedPhysicalWidth = physicalWidth;
297 double extendedPhysicalHeight = physicalHeight;
298 double logicalRatio = extendedLogicalWidth / extendedLogicalHeight;
299 double physicalRatio = extendedPhysicalWidth / extendedPhysicalHeight;
301 if (m_align == SVG_PRESERVEASPECTRATIO_NONE) {
302 transform.scaleNonUniform(extendedPhysicalWidth / extendedLogicalWidth, extendedPhysicalHeight / extendedLogicalHeight);
303 transform.translate(-extendedLogicalX, -extendedLogicalY);
304 return transform;
307 if ((logicalRatio < physicalRatio && (m_meetOrSlice == SVG_MEETORSLICE_MEET)) || (logicalRatio >= physicalRatio && (m_meetOrSlice == SVG_MEETORSLICE_SLICE))) {
308 transform.scaleNonUniform(extendedPhysicalHeight / extendedLogicalHeight, extendedPhysicalHeight / extendedLogicalHeight);
310 if (m_align == SVG_PRESERVEASPECTRATIO_XMINYMIN || m_align == SVG_PRESERVEASPECTRATIO_XMINYMID || m_align == SVG_PRESERVEASPECTRATIO_XMINYMAX)
311 transform.translate(-extendedLogicalX, -extendedLogicalY);
312 else if (m_align == SVG_PRESERVEASPECTRATIO_XMIDYMIN || m_align == SVG_PRESERVEASPECTRATIO_XMIDYMID || m_align == SVG_PRESERVEASPECTRATIO_XMIDYMAX)
313 transform.translate(-extendedLogicalX - (extendedLogicalWidth - extendedPhysicalWidth * extendedLogicalHeight / extendedPhysicalHeight) / 2, -extendedLogicalY);
314 else
315 transform.translate(-extendedLogicalX - (extendedLogicalWidth - extendedPhysicalWidth * extendedLogicalHeight / extendedPhysicalHeight), -extendedLogicalY);
317 return transform;
320 transform.scaleNonUniform(extendedPhysicalWidth / extendedLogicalWidth, extendedPhysicalWidth / extendedLogicalWidth);
322 if (m_align == SVG_PRESERVEASPECTRATIO_XMINYMIN || m_align == SVG_PRESERVEASPECTRATIO_XMIDYMIN || m_align == SVG_PRESERVEASPECTRATIO_XMAXYMIN)
323 transform.translate(-extendedLogicalX, -extendedLogicalY);
324 else if (m_align == SVG_PRESERVEASPECTRATIO_XMINYMID || m_align == SVG_PRESERVEASPECTRATIO_XMIDYMID || m_align == SVG_PRESERVEASPECTRATIO_XMAXYMID)
325 transform.translate(-extendedLogicalX, -extendedLogicalY - (extendedLogicalHeight - extendedPhysicalHeight * extendedLogicalWidth / extendedPhysicalWidth) / 2);
326 else
327 transform.translate(-extendedLogicalX, -extendedLogicalY - (extendedLogicalHeight - extendedPhysicalHeight * extendedLogicalWidth / extendedPhysicalWidth));
329 return transform;
332 String SVGPreserveAspectRatio::valueAsString() const
334 String alignType;
336 switch (m_align) {
337 case SVG_PRESERVEASPECTRATIO_NONE:
338 alignType = "none";
339 break;
340 case SVG_PRESERVEASPECTRATIO_XMINYMIN:
341 alignType = "xMinYMin";
342 break;
343 case SVG_PRESERVEASPECTRATIO_XMIDYMIN:
344 alignType = "xMidYMin";
345 break;
346 case SVG_PRESERVEASPECTRATIO_XMAXYMIN:
347 alignType = "xMaxYMin";
348 break;
349 case SVG_PRESERVEASPECTRATIO_XMINYMID:
350 alignType = "xMinYMid";
351 break;
352 case SVG_PRESERVEASPECTRATIO_XMIDYMID:
353 alignType = "xMidYMid";
354 break;
355 case SVG_PRESERVEASPECTRATIO_XMAXYMID:
356 alignType = "xMaxYMid";
357 break;
358 case SVG_PRESERVEASPECTRATIO_XMINYMAX:
359 alignType = "xMinYMax";
360 break;
361 case SVG_PRESERVEASPECTRATIO_XMIDYMAX:
362 alignType = "xMidYMax";
363 break;
364 case SVG_PRESERVEASPECTRATIO_XMAXYMAX:
365 alignType = "xMaxYMax";
366 break;
367 case SVG_PRESERVEASPECTRATIO_UNKNOWN:
368 alignType = "unknown";
369 break;
372 switch (m_meetOrSlice) {
373 default:
374 case SVG_MEETORSLICE_UNKNOWN:
375 return alignType;
376 case SVG_MEETORSLICE_MEET:
377 return alignType + " meet";
378 case SVG_MEETORSLICE_SLICE:
379 return alignType + " slice";
383 void SVGPreserveAspectRatio::add(PassRefPtrWillBeRawPtr<SVGPropertyBase> other, SVGElement*)
385 ASSERT_NOT_REACHED();
388 void SVGPreserveAspectRatio::calculateAnimatedValue(SVGAnimationElement* animationElement, float percentage, unsigned repeatCount, PassRefPtrWillBeRawPtr<SVGPropertyBase> fromValue, PassRefPtrWillBeRawPtr<SVGPropertyBase> toValue, PassRefPtrWillBeRawPtr<SVGPropertyBase>, SVGElement*)
390 ASSERT(animationElement);
392 bool useToValue;
393 animationElement->animateDiscreteType(percentage, false, true, useToValue);
395 RefPtrWillBeRawPtr<SVGPreserveAspectRatio> preserveAspectRatioToUse = useToValue ? toSVGPreserveAspectRatio(toValue) : toSVGPreserveAspectRatio(fromValue);
397 m_align = preserveAspectRatioToUse->m_align;
398 m_meetOrSlice = preserveAspectRatioToUse->m_meetOrSlice;
401 float SVGPreserveAspectRatio::calculateDistance(PassRefPtrWillBeRawPtr<SVGPropertyBase> toValue, SVGElement* contextElement)
403 // No paced animations for SVGPreserveAspectRatio.
404 return -1;