1/* 2 * Copyright (C) 2007, 2010 Rob Buis <buis@kde.org> 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 */ 19 20#include "config.h" 21#include "SVGViewSpec.h" 22 23#include "Document.h" 24#include "SVGAnimatedTransformList.h" 25#include "SVGFitToViewBox.h" 26#include "SVGNames.h" 27#include "SVGParserUtilities.h" 28#include "SVGSVGElement.h" 29#include "SVGTransformable.h" 30 31namespace WebCore { 32 33// Define custom animated property 'viewBox'. 34const SVGPropertyInfo* SVGViewSpec::viewBoxPropertyInfo() 35{ 36 static const SVGPropertyInfo* s_propertyInfo = 0; 37 if (!s_propertyInfo) { 38 s_propertyInfo = new SVGPropertyInfo(AnimatedRect, 39 PropertyIsReadOnly, 40 SVGNames::viewBoxAttr, 41 viewBoxIdentifier(), 42 0, 43 0); 44 } 45 return s_propertyInfo; 46} 47 48// Define custom animated property 'preserveAspectRatio'. 49const SVGPropertyInfo* SVGViewSpec::preserveAspectRatioPropertyInfo() 50{ 51 static const SVGPropertyInfo* s_propertyInfo = 0; 52 if (!s_propertyInfo) { 53 s_propertyInfo = new SVGPropertyInfo(AnimatedPreserveAspectRatio, 54 PropertyIsReadOnly, 55 SVGNames::preserveAspectRatioAttr, 56 preserveAspectRatioIdentifier(), 57 0, 58 0); 59 } 60 return s_propertyInfo; 61} 62 63 64// Define custom non-animated property 'transform'. 65const SVGPropertyInfo* SVGViewSpec::transformPropertyInfo() 66{ 67 static const SVGPropertyInfo* s_propertyInfo = 0; 68 if (!s_propertyInfo) { 69 s_propertyInfo = new SVGPropertyInfo(AnimatedTransformList, 70 PropertyIsReadOnly, 71 SVGNames::transformAttr, 72 transformIdentifier(), 73 0, 74 0); 75 } 76 return s_propertyInfo; 77} 78 79SVGViewSpec::SVGViewSpec(SVGElement* contextElement) 80 : m_contextElement(contextElement) 81 , m_zoomAndPan(SVGZoomAndPanMagnify) 82{ 83 ASSERT(m_contextElement); 84} 85 86const AtomicString& SVGViewSpec::viewBoxIdentifier() 87{ 88 DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGViewSpecViewBoxAttribute", AtomicString::ConstructFromLiteral)); 89 return s_identifier; 90} 91 92const AtomicString& SVGViewSpec::preserveAspectRatioIdentifier() 93{ 94 DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGViewSpecPreserveAspectRatioAttribute", AtomicString::ConstructFromLiteral)); 95 return s_identifier; 96} 97 98const AtomicString& SVGViewSpec::transformIdentifier() 99{ 100 DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGViewSpecTransformAttribute", AtomicString::ConstructFromLiteral)); 101 return s_identifier; 102} 103 104void SVGViewSpec::setZoomAndPan(unsigned short, ExceptionCode& ec) 105{ 106 // SVGViewSpec and all of its content is read-only. 107 ec = NO_MODIFICATION_ALLOWED_ERR; 108} 109 110void SVGViewSpec::setTransformString(const String& transform) 111{ 112 if (!m_contextElement) 113 return; 114 115 SVGTransformList newList; 116 newList.parse(transform); 117 118 if (SVGAnimatedProperty* wrapper = SVGAnimatedProperty::lookupWrapper<SVGElement, SVGAnimatedTransformList>(m_contextElement, transformPropertyInfo())) 119 static_cast<SVGAnimatedTransformList*>(wrapper)->detachListWrappers(newList.size()); 120 121 m_transform = newList; 122} 123 124String SVGViewSpec::transformString() const 125{ 126 return SVGPropertyTraits<SVGTransformList>::toString(m_transform); 127} 128 129String SVGViewSpec::viewBoxString() const 130{ 131 return SVGPropertyTraits<FloatRect>::toString(viewBoxBaseValue()); 132} 133 134String SVGViewSpec::preserveAspectRatioString() const 135{ 136 return SVGPropertyTraits<SVGPreserveAspectRatio>::toString(preserveAspectRatioBaseValue()); 137} 138 139SVGElement* SVGViewSpec::viewTarget() const 140{ 141 if (!m_contextElement) 142 return 0; 143 Element* element = m_contextElement->treeScope().getElementById(m_viewTargetString); 144 if (!element || !element->isSVGElement()) 145 return 0; 146 return toSVGElement(element); 147} 148 149SVGTransformListPropertyTearOff* SVGViewSpec::transform() 150{ 151 if (!m_contextElement) 152 return 0; 153 // Return the animVal here, as its readonly by default - which is exactly what we want here. 154 return static_cast<SVGTransformListPropertyTearOff*>(static_pointer_cast<SVGAnimatedTransformList>(lookupOrCreateTransformWrapper(this))->animVal()); 155} 156 157PassRefPtr<SVGAnimatedRect> SVGViewSpec::viewBoxAnimated() 158{ 159 if (!m_contextElement) 160 return 0; 161 return static_pointer_cast<SVGAnimatedRect>(lookupOrCreateViewBoxWrapper(this)); 162} 163 164PassRefPtr<SVGAnimatedPreserveAspectRatio> SVGViewSpec::preserveAspectRatioAnimated() 165{ 166 if (!m_contextElement) 167 return 0; 168 return static_pointer_cast<SVGAnimatedPreserveAspectRatio>(lookupOrCreatePreserveAspectRatioWrapper(this)); 169} 170 171PassRefPtr<SVGAnimatedProperty> SVGViewSpec::lookupOrCreateViewBoxWrapper(SVGViewSpec* ownerType) 172{ 173 ASSERT(ownerType); 174 ASSERT(ownerType->contextElement()); 175 return SVGAnimatedProperty::lookupOrCreateWrapper<SVGElement, SVGAnimatedRect, FloatRect>(ownerType->contextElement(), viewBoxPropertyInfo(), ownerType->m_viewBox); 176} 177 178PassRefPtr<SVGAnimatedProperty> SVGViewSpec::lookupOrCreatePreserveAspectRatioWrapper(SVGViewSpec* ownerType) 179{ 180 ASSERT(ownerType); 181 ASSERT(ownerType->contextElement()); 182 return SVGAnimatedProperty::lookupOrCreateWrapper<SVGElement, SVGAnimatedPreserveAspectRatio, SVGPreserveAspectRatio>(ownerType->contextElement(), preserveAspectRatioPropertyInfo(), ownerType->m_preserveAspectRatio); 183} 184 185PassRefPtr<SVGAnimatedProperty> SVGViewSpec::lookupOrCreateTransformWrapper(SVGViewSpec* ownerType) 186{ 187 ASSERT(ownerType); 188 ASSERT(ownerType->contextElement()); 189 return SVGAnimatedProperty::lookupOrCreateWrapper<SVGElement, SVGAnimatedTransformList, SVGTransformList>(ownerType->contextElement(), transformPropertyInfo(), ownerType->m_transform); 190} 191 192void SVGViewSpec::reset() 193{ 194 m_zoomAndPan = SVGZoomAndPanMagnify; 195 m_transform.clear(); 196 m_viewBox = FloatRect(); 197 m_preserveAspectRatio = SVGPreserveAspectRatio(); 198 m_viewTargetString = emptyString(); 199} 200 201static const UChar svgViewSpec[] = {'s', 'v', 'g', 'V', 'i', 'e', 'w'}; 202static const UChar viewBoxSpec[] = {'v', 'i', 'e', 'w', 'B', 'o', 'x'}; 203static const UChar preserveAspectRatioSpec[] = {'p', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'A', 's', 'p', 'e', 'c', 't', 'R', 'a', 't', 'i', 'o'}; 204static const UChar transformSpec[] = {'t', 'r', 'a', 'n', 's', 'f', 'o', 'r', 'm'}; 205static const UChar zoomAndPanSpec[] = {'z', 'o', 'o', 'm', 'A', 'n', 'd', 'P', 'a', 'n'}; 206static const UChar viewTargetSpec[] = {'v', 'i', 'e', 'w', 'T', 'a', 'r', 'g', 'e', 't'}; 207 208bool SVGViewSpec::parseViewSpec(const String& viewSpec) 209{ 210 auto upconvertedCharacters = StringView(viewSpec).upconvertedCharacters(); 211 const UChar* currViewSpec = upconvertedCharacters; 212 const UChar* end = currViewSpec + viewSpec.length(); 213 214 if (currViewSpec >= end || !m_contextElement) 215 return false; 216 217 if (!skipString(currViewSpec, end, svgViewSpec, WTF_ARRAY_LENGTH(svgViewSpec))) 218 return false; 219 220 if (currViewSpec >= end || *currViewSpec != '(') 221 return false; 222 currViewSpec++; 223 224 while (currViewSpec < end && *currViewSpec != ')') { 225 if (*currViewSpec == 'v') { 226 if (skipString(currViewSpec, end, viewBoxSpec, WTF_ARRAY_LENGTH(viewBoxSpec))) { 227 if (currViewSpec >= end || *currViewSpec != '(') 228 return false; 229 currViewSpec++; 230 FloatRect viewBox; 231 if (!SVGFitToViewBox::parseViewBox(&m_contextElement->document(), currViewSpec, end, viewBox, false)) 232 return false; 233 setViewBoxBaseValue(viewBox); 234 if (currViewSpec >= end || *currViewSpec != ')') 235 return false; 236 currViewSpec++; 237 } else if (skipString(currViewSpec, end, viewTargetSpec, WTF_ARRAY_LENGTH(viewTargetSpec))) { 238 if (currViewSpec >= end || *currViewSpec != '(') 239 return false; 240 const UChar* viewTargetStart = ++currViewSpec; 241 while (currViewSpec < end && *currViewSpec != ')') 242 currViewSpec++; 243 if (currViewSpec >= end) 244 return false; 245 setViewTargetString(String(viewTargetStart, currViewSpec - viewTargetStart)); 246 currViewSpec++; 247 } else 248 return false; 249 } else if (*currViewSpec == 'z') { 250 if (!skipString(currViewSpec, end, zoomAndPanSpec, WTF_ARRAY_LENGTH(zoomAndPanSpec))) 251 return false; 252 if (currViewSpec >= end || *currViewSpec != '(') 253 return false; 254 currViewSpec++; 255 if (!parseZoomAndPan(currViewSpec, end, m_zoomAndPan)) 256 return false; 257 if (currViewSpec >= end || *currViewSpec != ')') 258 return false; 259 currViewSpec++; 260 } else if (*currViewSpec == 'p') { 261 if (!skipString(currViewSpec, end, preserveAspectRatioSpec, WTF_ARRAY_LENGTH(preserveAspectRatioSpec))) 262 return false; 263 if (currViewSpec >= end || *currViewSpec != '(') 264 return false; 265 currViewSpec++; 266 SVGPreserveAspectRatio preserveAspectRatio; 267 if (!preserveAspectRatio.parse(currViewSpec, end, false)) 268 return false; 269 setPreserveAspectRatioBaseValue(preserveAspectRatio); 270 if (currViewSpec >= end || *currViewSpec != ')') 271 return false; 272 currViewSpec++; 273 } else if (*currViewSpec == 't') { 274 if (!skipString(currViewSpec, end, transformSpec, WTF_ARRAY_LENGTH(transformSpec))) 275 return false; 276 if (currViewSpec >= end || *currViewSpec != '(') 277 return false; 278 currViewSpec++; 279 SVGTransformable::parseTransformAttribute(m_transform, currViewSpec, end, SVGTransformable::DoNotClearList); 280 if (currViewSpec >= end || *currViewSpec != ')') 281 return false; 282 currViewSpec++; 283 } else 284 return false; 285 286 if (currViewSpec < end && *currViewSpec == ';') 287 currViewSpec++; 288 } 289 290 if (currViewSpec >= end || *currViewSpec != ')') 291 return false; 292 293 return true; 294} 295 296} 297