File indexing completed on 2024-04-28 15:24:43

0001 /*
0002     Copyright (C) 2007 Rob Buis <buis@kde.org>
0003 
0004     This file is part of the KDE project
0005 
0006     This library is free software; you can redistribute it and/or
0007     modify it under the terms of the GNU Library General Public
0008     License as published by the Free Software Foundation; either
0009     version 2 of the License, or (at your option) any later version.
0010 
0011     This library is distributed in the hope that it will be useful,
0012     but WITHOUT ANY WARRANTY; without even the implied warranty of
0013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014     Library General Public License for more details.
0015 
0016     You should have received a copy of the GNU Library General Public License
0017     along with this library; see the file COPYING.LIB.  If not, write to
0018     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019     Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #include "wtf/Platform.h"
0023 #if ENABLE(SVG)
0024 #include "SVGViewSpec.h"
0025 
0026 #include "PlatformString.h"
0027 #include "SVGParserUtilities.h"
0028 #include "SVGPreserveAspectRatio.h"
0029 #include "SVGSVGElement.h"
0030 #include "SVGTransformList.h"
0031 #include "SVGTransformable.h"
0032 
0033 namespace WebCore
0034 {
0035 
0036 SVGViewSpec::SVGViewSpec(const SVGSVGElement *contextElement)
0037     : SVGFitToViewBox()
0038     , SVGZoomAndPan()
0039     , m_transform(SVGTransformList::create(SVGNames::transformAttr))
0040     , m_contextElement(contextElement)
0041 {
0042 }
0043 
0044 SVGViewSpec::~SVGViewSpec()
0045 {
0046 }
0047 
0048 void SVGViewSpec::setTransform(const String &transform)
0049 {
0050     SVGTransformable::parseTransformAttribute(m_transform.get(), transform);
0051 }
0052 
0053 void SVGViewSpec::setViewBoxString(const String &viewBox)
0054 {
0055     float x, y, w, h;
0056     const UChar *c = viewBox.characters();
0057     const UChar *end = c + viewBox.length();
0058     if (!parseViewBox(c, end, x, y, w, h, false)) {
0059         return;
0060     }
0061     setViewBoxBaseValue(FloatRect(x, y, w, h));
0062 }
0063 
0064 void SVGViewSpec::setPreserveAspectRatioString(const String &preserve)
0065 {
0066     const UChar *c = preserve.characters();
0067     const UChar *end = c + preserve.length();
0068     preserveAspectRatioBaseValue()->parsePreserveAspectRatio(c, end);
0069 }
0070 
0071 void SVGViewSpec::setViewTargetString(const String &viewTargetString)
0072 {
0073     m_viewTargetString = viewTargetString;
0074 }
0075 
0076 SVGElement *SVGViewSpec::viewTarget() const
0077 {
0078     return static_cast<SVGElement *>(m_contextElement->ownerDocument()->getElementById(m_viewTargetString));
0079 }
0080 
0081 const SVGElement *SVGViewSpec::contextElement() const
0082 {
0083     return m_contextElement;
0084 }
0085 
0086 static const UChar svgViewSpec[] = {'s', 'v', 'g', 'V', 'i', 'e', 'w'};
0087 static const UChar viewBoxSpec[] = {'v', 'i', 'e', 'w', 'B', 'o', 'x'};
0088 static const UChar preserveAspectRatioSpec[] = {'p', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'A', 's', 'p', 'e', 'c', 't', 'R', 'a', 't', 'i', 'o'};
0089 static const UChar transformSpec[] = {'t', 'r', 'a', 'n', 's', 'f', 'o', 'r', 'm'};
0090 static const UChar zoomAndPanSpec[] = {'z', 'o', 'o', 'm', 'A', 'n', 'd', 'P', 'a', 'n'};
0091 static const UChar viewTargetSpec[] =  {'v', 'i', 'e', 'w', 'T', 'a', 'r', 'g', 'e', 't'};
0092 
0093 bool SVGViewSpec::parseViewSpec(const String &viewSpec)
0094 {
0095     const UChar *currViewSpec = viewSpec.characters();
0096     const UChar *end = currViewSpec + viewSpec.length();
0097 
0098     if (currViewSpec >= end) {
0099         return false;
0100     }
0101 
0102     if (!skipString(currViewSpec, end, svgViewSpec, sizeof(svgViewSpec) / sizeof(UChar))) {
0103         return false;
0104     }
0105 
0106     if (currViewSpec >= end || *currViewSpec != '(') {
0107         return false;
0108     }
0109     currViewSpec++;
0110 
0111     while (currViewSpec < end && *currViewSpec != ')') {
0112         if (*currViewSpec == 'v') {
0113             if (skipString(currViewSpec, end, viewBoxSpec, sizeof(viewBoxSpec) / sizeof(UChar))) {
0114                 if (currViewSpec >= end || *currViewSpec != '(') {
0115                     return false;
0116                 }
0117                 currViewSpec++;
0118                 float x, y, w, h;
0119                 if (!parseViewBox(currViewSpec, end, x, y, w, h, false)) {
0120                     return false;
0121                 }
0122                 setViewBoxBaseValue(FloatRect(x, y, w, h));
0123                 if (currViewSpec >= end || *currViewSpec != ')') {
0124                     return false;
0125                 }
0126                 currViewSpec++;
0127             } else if (skipString(currViewSpec, end, viewTargetSpec, sizeof(viewTargetSpec) / sizeof(UChar))) {
0128                 if (currViewSpec >= end || *currViewSpec != '(') {
0129                     return false;
0130                 }
0131                 const UChar *viewTargetStart = ++currViewSpec;
0132                 while (currViewSpec < end && *currViewSpec != ')') {
0133                     currViewSpec++;
0134                 }
0135                 if (currViewSpec >= end) {
0136                     return false;
0137                 }
0138                 setViewTargetString(String(viewTargetStart, currViewSpec - viewTargetStart));
0139                 currViewSpec++;
0140             } else {
0141                 return false;
0142             }
0143         } else if (*currViewSpec == 'z') {
0144             if (!skipString(currViewSpec, end, zoomAndPanSpec, sizeof(zoomAndPanSpec) / sizeof(UChar))) {
0145                 return false;
0146             }
0147             if (currViewSpec >= end || *currViewSpec != '(') {
0148                 return false;
0149             }
0150             currViewSpec++;
0151             if (!parseZoomAndPan(currViewSpec, end)) {
0152                 return false;
0153             }
0154             if (currViewSpec >= end || *currViewSpec != ')') {
0155                 return false;
0156             }
0157             currViewSpec++;
0158         } else if (*currViewSpec == 'p') {
0159             if (!skipString(currViewSpec, end, preserveAspectRatioSpec, sizeof(preserveAspectRatioSpec) / sizeof(UChar))) {
0160                 return false;
0161             }
0162             if (currViewSpec >= end || *currViewSpec != '(') {
0163                 return false;
0164             }
0165             currViewSpec++;
0166             if (!preserveAspectRatioBaseValue()->parsePreserveAspectRatio(currViewSpec, end, false)) {
0167                 return false;
0168             }
0169             if (currViewSpec >= end || *currViewSpec != ')') {
0170                 return false;
0171             }
0172             currViewSpec++;
0173         } else if (*currViewSpec == 't') {
0174             if (!skipString(currViewSpec, end, transformSpec, sizeof(transformSpec) / sizeof(UChar))) {
0175                 return false;
0176             }
0177             if (currViewSpec >= end || *currViewSpec != '(') {
0178                 return false;
0179             }
0180             currViewSpec++;
0181             SVGTransformable::parseTransformAttribute(m_transform.get(), currViewSpec, end);
0182             if (currViewSpec >= end || *currViewSpec != ')') {
0183                 return false;
0184             }
0185             currViewSpec++;
0186         } else {
0187             return false;
0188         }
0189 
0190         if (currViewSpec < end && *currViewSpec == ';') {
0191             currViewSpec++;
0192         }
0193     }
0194 
0195     if (currViewSpec >= end || *currViewSpec != ')') {
0196         return false;
0197     }
0198 
0199     return true;
0200 }
0201 
0202 }
0203 
0204 #endif // ENABLE(SVG)