WebCore:
[WebKit-https.git] / WebCore / svg / SVGPreserveAspectRatio.cpp
1 /*
2     Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org>
3                   2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4
5     This file is part of the KDE project
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 #if ENABLE(SVG)
25 #include "SVGPreserveAspectRatio.h"
26
27 #include "SVGParserUtilities.h"
28 #include "SVGSVGElement.h"
29
30 namespace WebCore {
31
32 SVGPreserveAspectRatio::SVGPreserveAspectRatio()
33     : RefCounted<SVGPreserveAspectRatio>()
34     , m_align(SVG_PRESERVEASPECTRATIO_XMIDYMID)
35     , m_meetOrSlice(SVG_MEETORSLICE_MEET)
36 {
37     // FIXME: Should the two values default to UNKNOWN instead?
38 }
39
40 SVGPreserveAspectRatio::~SVGPreserveAspectRatio()
41 {
42 }
43
44 void SVGPreserveAspectRatio::setAlign(unsigned short align)
45 {
46     m_align = align;
47 }
48
49 unsigned short SVGPreserveAspectRatio::align() const
50 {
51     return m_align;
52 }
53
54 void SVGPreserveAspectRatio::setMeetOrSlice(unsigned short meetOrSlice)
55 {
56     m_meetOrSlice = meetOrSlice;
57 }
58
59 unsigned short SVGPreserveAspectRatio::meetOrSlice() const
60 {
61     return m_meetOrSlice;
62 }
63
64 bool SVGPreserveAspectRatio::parsePreserveAspectRatio(const UChar*& currParam, const UChar* end, bool validate)
65 {
66     SVGPreserveAspectRatioType align = SVG_PRESERVEASPECTRATIO_NONE;
67     SVGMeetOrSliceType meetOrSlice = SVG_MEETORSLICE_MEET;
68     bool ret = false;
69
70     if (!skipOptionalSpaces(currParam, end))
71         goto bail_out;
72
73     if (*currParam == 'd') {
74         if (!skipString(currParam, end, "defer"))
75             goto bail_out;
76         // FIXME: We just ignore the "defer" here.
77         if (!skipOptionalSpaces(currParam, end))
78             goto bail_out;
79     }
80
81     if (*currParam == 'n') {
82         if (!skipString(currParam, end, "none"))
83             goto bail_out;
84         skipOptionalSpaces(currParam, end);
85     } else if (*currParam == 'x') {
86         if ((end - currParam) < 8)
87             goto bail_out;
88         if (currParam[1] != 'M' || currParam[4] != 'Y' || currParam[5] != 'M')
89             goto bail_out;
90         if (currParam[2] == 'i') {
91             if (currParam[3] == 'n') {
92                 if (currParam[6] == 'i') {
93                     if (currParam[7] == 'n')
94                         align = SVG_PRESERVEASPECTRATIO_XMINYMIN;
95                     else if (currParam[7] == 'd')
96                         align = SVG_PRESERVEASPECTRATIO_XMINYMID;
97                     else
98                         goto bail_out;
99                 } else if (currParam[6] == 'a' && currParam[7] == 'x')
100                      align = SVG_PRESERVEASPECTRATIO_XMINYMAX;
101                 else
102                      goto bail_out;
103              } else if (currParam[3] == 'd') {
104                 if (currParam[6] == 'i') {
105                     if (currParam[7] == 'n')
106                         align = SVG_PRESERVEASPECTRATIO_XMIDYMIN;
107                     else if (currParam[7] == 'd')
108                         align = SVG_PRESERVEASPECTRATIO_XMIDYMID;
109                     else
110                         goto bail_out;
111                 } else if (currParam[6] == 'a' && currParam[7] == 'x')
112                     align = SVG_PRESERVEASPECTRATIO_XMIDYMAX;
113                 else
114                     goto bail_out;
115             } else
116                 goto bail_out;
117         } else if (currParam[2] == 'a' && currParam[3] == 'x') {
118             if (currParam[6] == 'i') {
119                 if (currParam[7] == 'n')
120                     align = SVG_PRESERVEASPECTRATIO_XMAXYMIN;
121                 else if (currParam[7] == 'd')
122                     align = SVG_PRESERVEASPECTRATIO_XMAXYMID;
123                 else
124                     goto bail_out;
125             } else if (currParam[6] == 'a' && currParam[7] == 'x')
126                 align = SVG_PRESERVEASPECTRATIO_XMAXYMAX;
127             else
128                 goto bail_out;
129         } else
130             goto bail_out;
131         currParam += 8;
132         skipOptionalSpaces(currParam, end);
133     } else
134         goto bail_out;
135
136     if (currParam < end) {
137         if (*currParam == 'm') {
138             if (!skipString(currParam, end, "meet"))
139                 goto bail_out;
140             skipOptionalSpaces(currParam, end);
141         } else if (*currParam == 's') {
142             if (!skipString(currParam, end, "slice"))
143                 goto bail_out;
144             skipOptionalSpaces(currParam, end);
145             if (align != SVG_PRESERVEASPECTRATIO_NONE)
146                 meetOrSlice = SVG_MEETORSLICE_SLICE;    
147         }
148     }
149
150     if (end != currParam && validate) {
151 bail_out:
152         // FIXME: Should the two values be set to UNKNOWN instead?
153         align = SVG_PRESERVEASPECTRATIO_NONE;
154         meetOrSlice = SVG_MEETORSLICE_MEET;
155     } else
156         ret = true;
157
158     if (m_align == align && m_meetOrSlice == meetOrSlice)
159         return ret;
160
161     m_align = align;
162     m_meetOrSlice = meetOrSlice;
163     return ret;
164 }
165
166 AffineTransform SVGPreserveAspectRatio::getCTM(double logicX, double logicY,
167                                                double logicWidth, double logicHeight,
168                                                double /*physX*/, double /*physY*/,
169                                                double physWidth, double physHeight)
170 {
171     AffineTransform temp;
172
173     if (align() == SVG_PRESERVEASPECTRATIO_UNKNOWN)
174         return temp;
175
176     double vpar = logicWidth / logicHeight;
177     double svgar = physWidth / physHeight;
178
179     if (align() == SVG_PRESERVEASPECTRATIO_NONE) {
180         temp.scale(physWidth / logicWidth, physHeight / logicHeight);
181         temp.translate(-logicX, -logicY);
182     } else if (vpar < svgar && (meetOrSlice() == SVG_MEETORSLICE_MEET) || vpar >= svgar && (meetOrSlice() == SVG_MEETORSLICE_SLICE)) {
183         temp.scale(physHeight / logicHeight, physHeight / logicHeight);
184
185         if (align() == SVG_PRESERVEASPECTRATIO_XMINYMIN || align() == SVG_PRESERVEASPECTRATIO_XMINYMID || align() == SVG_PRESERVEASPECTRATIO_XMINYMAX)
186             temp.translate(-logicX, -logicY);
187         else if (align() == SVG_PRESERVEASPECTRATIO_XMIDYMIN || align() == SVG_PRESERVEASPECTRATIO_XMIDYMID || align() == SVG_PRESERVEASPECTRATIO_XMIDYMAX)
188             temp.translate(-logicX - (logicWidth - physWidth * logicHeight / physHeight) / 2, -logicY);
189         else
190             temp.translate(-logicX - (logicWidth - physWidth * logicHeight / physHeight), -logicY);
191     } else {
192         temp.scale(physWidth / logicWidth, physWidth / logicWidth);
193
194         if (align() == SVG_PRESERVEASPECTRATIO_XMINYMIN || align() == SVG_PRESERVEASPECTRATIO_XMIDYMIN || align() == SVG_PRESERVEASPECTRATIO_XMAXYMIN)
195             temp.translate(-logicX, -logicY);
196         else if (align() == SVG_PRESERVEASPECTRATIO_XMINYMID || align() == SVG_PRESERVEASPECTRATIO_XMIDYMID || align() == SVG_PRESERVEASPECTRATIO_XMAXYMID)
197             temp.translate(-logicX, -logicY - (logicHeight - physHeight * logicWidth / physWidth) / 2);
198         else
199             temp.translate(-logicX, -logicY - (logicHeight - physHeight * logicWidth / physWidth));
200     }
201
202     return temp;
203 }
204
205 }
206
207 // vim:ts=4:noet
208 #endif // ENABLE(SVG)