Reviewed by weinig.
[WebKit-https.git] / WebCore / ksvg2 / svg / SVGPreserveAspectRatio.cpp
1 /*
2     Copyright (C) 2004, 2005 Nikolas Zimmermann <wildfox@kde.org>
3                   2004, 2005, 2006 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., 59 Temple Place - Suite 330,
20     Boston, MA 02111-1307, USA.
21 */
22
23 #include "config.h"
24 #ifdef SVG_SUPPORT
25 #include "SVGPreserveAspectRatio.h"
26
27 #include "SVGParserUtilities.h"
28 #include "SVGSVGElement.h"
29
30 namespace WebCore {
31
32 SVGPreserveAspectRatio::SVGPreserveAspectRatio(const SVGStyledElement* context)
33     : Shared<SVGPreserveAspectRatio>()
34     , m_align(SVG_PRESERVEASPECTRATIO_XMIDYMID)
35     , m_meetOrSlice(SVG_MEETORSLICE_MEET)
36     , m_context(context)
37 {
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 static const UChar deferDesc[] =  {'d', 'e', 'f', 'e', 'r'};
65 static const UChar noneDesc[] =  {'n', 'o', 'n', 'e'};
66 static const UChar meetDesc[] =  {'m', 'e', 'e', 't'};
67 static const UChar sliceDesc[] =  {'s', 'l', 'i', 'c', 'e'};
68 static const UChar xMinYMinDesc[] =  {'x', 'M', 'i', 'n', 'Y', 'M', 'i', 'n'};
69 static const UChar xMinYMidDesc[] =  {'x', 'M', 'i', 'n', 'Y', 'M', 'i', 'd'};
70 static const UChar xMinYMaxDesc[] =  {'x', 'M', 'i', 'n', 'Y', 'M', 'a', 'x'};
71 static const UChar xMidYMinDesc[] =  {'x', 'M', 'i', 'd', 'Y', 'M', 'i', 'n'};
72 static const UChar xMidYMidDesc[] =  {'x', 'M', 'i', 'd', 'Y', 'M', 'i', 'd'};
73 static const UChar xMidYMaxDesc[] =  {'x', 'M', 'i', 'd', 'Y', 'M', 'a', 'x'};
74 static const UChar xMaxYMinDesc[] =  {'x', 'M', 'a', 'x', 'Y', 'M', 'i', 'n'};
75 static const UChar xMaxYMidDesc[] =  {'x', 'M', 'a', 'x', 'Y', 'M', 'i', 'd'};
76 static const UChar xMaxYMaxDesc[] =  {'x', 'M', 'a', 'x', 'Y', 'M', 'a', 'x'};
77
78 void SVGPreserveAspectRatio::parsePreserveAspectRatio(const String& string)
79 {
80     // Spec: set the defaults
81     SVGPreserveAspectRatioType align = SVG_PRESERVEASPECTRATIO_NONE;
82     SVGMeetOrSliceType meetOrSlice = SVG_MEETORSLICE_MEET;
83
84     const UChar* currParam = string.characters();
85     const UChar* end = currParam + string.length();
86
87     if (!skipOptionalSpaces(currParam, end))
88         goto bail_out;
89
90     if (*currParam == 'd') {
91         if (!checkString(currParam, end, deferDesc, sizeof(deferDesc) / sizeof(UChar)))
92             goto bail_out;
93         skipOptionalSpaces(currParam, end);
94     }
95
96     if (*currParam == 'n') {
97         if (!checkString(currParam, end, noneDesc, sizeof(noneDesc) / sizeof(UChar)))
98             goto bail_out;
99         skipOptionalSpaces(currParam, end);
100         align = SVG_PRESERVEASPECTRATIO_NONE;
101     } else if (*currParam == 'x') {
102         if ((end - currParam) < 8)
103             goto bail_out;
104         if (currParam[1] != 'M' || currParam[4] != 'Y' || currParam[5] != 'M')
105             goto bail_out;
106         if (currParam[2] == 'i') {
107             if (currParam[3] == 'n') {
108                 if (currParam[6] == 'i') {
109                     if (currParam[7] == 'n')
110                         align = SVG_PRESERVEASPECTRATIO_XMINYMIN;
111                     else if (currParam[7] == 'd')
112                         align = SVG_PRESERVEASPECTRATIO_XMINYMID;
113                     else
114                         goto bail_out;
115                 } else if (currParam[6] == 'a' && currParam[7] == 'x')
116                      align = SVG_PRESERVEASPECTRATIO_XMINYMAX;
117                 else
118                      goto bail_out;
119              } else if (currParam[3] == 'd') {
120                 if (currParam[6] == 'i') {
121                     if (currParam[7] == 'n')
122                         align = SVG_PRESERVEASPECTRATIO_XMIDYMIN;
123                     else if (currParam[7] == 'd')
124                         align = SVG_PRESERVEASPECTRATIO_XMIDYMID;
125                     else
126                         goto bail_out;
127                 } else if (currParam[6] == 'a' && currParam[7] == 'x')
128                     align = SVG_PRESERVEASPECTRATIO_XMIDYMAX;
129                 else
130                     goto bail_out;
131             } else
132                 goto bail_out;
133         } else if (currParam[2] == 'a' && currParam[3] == 'x') {
134             if (currParam[6] == 'i') {
135                 if (currParam[7] == 'n')
136                     align = SVG_PRESERVEASPECTRATIO_XMAXYMIN;
137                 else if (currParam[7] == 'd')
138                     align = SVG_PRESERVEASPECTRATIO_XMAXYMID;
139                 else
140                     goto bail_out;
141             } else if (currParam[6] == 'a' && currParam[7] == 'x')
142                 align = SVG_PRESERVEASPECTRATIO_XMAXYMAX;
143             else
144                 goto bail_out;
145         } else
146             goto bail_out;
147         currParam += 8;
148         skipOptionalSpaces(currParam, end);
149     }
150
151     if (*currParam == 'm') {
152         if (!checkString(currParam, end, meetDesc, sizeof(meetDesc) / sizeof(UChar)))
153             goto bail_out;
154         skipOptionalSpaces(currParam, end);
155         meetOrSlice = SVG_MEETORSLICE_MEET;
156     } else if (*currParam == 's') {
157         if (!checkString(currParam, end, sliceDesc, sizeof(sliceDesc) / sizeof(UChar)))
158             goto bail_out;
159         skipOptionalSpaces(currParam, end);
160         if (m_align != SVG_PRESERVEASPECTRATIO_NONE)
161             meetOrSlice = SVG_MEETORSLICE_SLICE;    
162     }
163
164     if (end != currParam)
165         goto bail_out; // FIXME: may need to print an error here
166
167     setAlign(align);
168     setMeetOrSlice(meetOrSlice);
169
170     if (m_context)
171         m_context->notifyAttributeChange();
172     return;
173
174 bail_out:
175     setAlign(SVG_PRESERVEASPECTRATIO_NONE);
176     setMeetOrSlice(SVG_MEETORSLICE_MEET);
177
178     if (m_context)
179         m_context->notifyAttributeChange();
180 }
181
182 AffineTransform SVGPreserveAspectRatio::getCTM(float logicX, float logicY,
183                                                float logicWidth, float logicHeight,
184                                                float /*physX*/, float /*physY*/,
185                                                float physWidth, float physHeight)
186 {
187     AffineTransform temp;
188
189     if (align() == SVG_PRESERVEASPECTRATIO_UNKNOWN)
190         return temp;
191
192     float vpar = logicWidth / logicHeight;
193     float svgar = physWidth / physHeight;
194
195     if (align() == SVG_PRESERVEASPECTRATIO_NONE) {
196         temp.scale(physWidth / logicWidth, physHeight / logicHeight);
197         temp.translate(-logicX, -logicY);
198     } else if (vpar < svgar && (meetOrSlice() == SVG_MEETORSLICE_MEET) || vpar >= svgar && (meetOrSlice() == SVG_MEETORSLICE_SLICE)) {
199         temp.scale(physHeight / logicHeight, physHeight / logicHeight);
200
201         if (align() == SVG_PRESERVEASPECTRATIO_XMINYMIN || align() == SVG_PRESERVEASPECTRATIO_XMINYMID || align() == SVG_PRESERVEASPECTRATIO_XMINYMAX)
202             temp.translate(-logicX, -logicY);
203         else if (align() == SVG_PRESERVEASPECTRATIO_XMIDYMIN || align() == SVG_PRESERVEASPECTRATIO_XMIDYMID || align() == SVG_PRESERVEASPECTRATIO_XMIDYMAX)
204             temp.translate(-logicX - (logicWidth - physWidth * logicHeight / physHeight) / 2, -logicY);
205         else
206             temp.translate(-logicX - (logicWidth - physWidth * logicHeight / physHeight), -logicY);
207     } else {
208         temp.scale(physWidth / logicWidth, physWidth / logicWidth);
209
210         if (align() == SVG_PRESERVEASPECTRATIO_XMINYMIN || align() == SVG_PRESERVEASPECTRATIO_XMIDYMIN || align() == SVG_PRESERVEASPECTRATIO_XMAXYMIN)
211             temp.translate(-logicX, -logicY);
212         else if (align() == SVG_PRESERVEASPECTRATIO_XMINYMID || align() == SVG_PRESERVEASPECTRATIO_XMIDYMID || align() == SVG_PRESERVEASPECTRATIO_XMAXYMID)
213             temp.translate(-logicX, -logicY - (logicHeight - physHeight * logicWidth / physWidth) / 2);
214         else
215             temp.translate(-logicX, -logicY - (logicHeight - physHeight * logicWidth / physWidth));
216     }
217
218     return temp;
219 }
220
221 }
222
223 // vim:ts=4:noet
224 #endif // SVG_SUPPORT
225