1 /* 2 * Copyright (C) 2007, 2010 Rob Buis <buis (at) 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 "core/svg/SVGViewSpec.h" 22 23 #include "SVGNames.h" 24 #include "bindings/v8/ExceptionState.h" 25 #include "core/dom/Document.h" 26 #include "core/svg/SVGAnimatedTransformList.h" 27 #include "core/svg/SVGParserUtilities.h" 28 29 namespace WebCore { 30 31 // Define custom animated property 'viewBox'. 32 const SVGPropertyInfo* SVGViewSpec::viewBoxPropertyInfo() 33 { 34 static const SVGPropertyInfo* s_propertyInfo = 0; 35 if (!s_propertyInfo) { 36 s_propertyInfo = new SVGPropertyInfo(AnimatedRect, 37 PropertyIsReadOnly, 38 SVGNames::viewBoxAttr, 39 viewBoxIdentifier(), 40 0, 41 0); 42 } 43 return s_propertyInfo; 44 } 45 46 // Define custom animated property 'preserveAspectRatio'. 47 const SVGPropertyInfo* SVGViewSpec::preserveAspectRatioPropertyInfo() 48 { 49 static const SVGPropertyInfo* s_propertyInfo = 0; 50 if (!s_propertyInfo) { 51 s_propertyInfo = new SVGPropertyInfo(AnimatedPreserveAspectRatio, 52 PropertyIsReadOnly, 53 SVGNames::preserveAspectRatioAttr, 54 preserveAspectRatioIdentifier(), 55 0, 56 0); 57 } 58 return s_propertyInfo; 59 } 60 61 62 // Define custom non-animated property 'transform'. 63 const SVGPropertyInfo* SVGViewSpec::transformPropertyInfo() 64 { 65 static const SVGPropertyInfo* s_propertyInfo = 0; 66 if (!s_propertyInfo) { 67 s_propertyInfo = new SVGPropertyInfo(AnimatedTransformList, 68 PropertyIsReadOnly, 69 SVGNames::transformAttr, 70 transformIdentifier(), 71 0, 72 0); 73 } 74 return s_propertyInfo; 75 } 76 77 SVGViewSpec::SVGViewSpec(WeakPtr<SVGSVGElement> contextElement) 78 : m_contextElement(contextElement) 79 , m_zoomAndPan(SVGZoomAndPanMagnify) 80 { 81 ASSERT(m_contextElement); 82 ScriptWrappable::init(this); 83 } 84 85 const AtomicString& SVGViewSpec::viewBoxIdentifier() 86 { 87 DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGViewSpecViewBoxAttribute", AtomicString::ConstructFromLiteral)); 88 return s_identifier; 89 } 90 91 const AtomicString& SVGViewSpec::preserveAspectRatioIdentifier() 92 { 93 DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGViewSpecPreserveAspectRatioAttribute", AtomicString::ConstructFromLiteral)); 94 return s_identifier; 95 } 96 97 const AtomicString& SVGViewSpec::transformIdentifier() 98 { 99 DEFINE_STATIC_LOCAL(AtomicString, s_identifier, ("SVGViewSpecTransformAttribute", AtomicString::ConstructFromLiteral)); 100 return s_identifier; 101 } 102 103 void SVGViewSpec::setZoomAndPan(unsigned short, ExceptionState& exceptionState) 104 { 105 // SVGViewSpec and all of its content is read-only. 106 exceptionState.throwUninformativeAndGenericDOMException(NoModificationAllowedError); 107 } 108 109 void SVGViewSpec::setTransformString(const String& transform) 110 { 111 if (!m_contextElement) 112 return; 113 114 SVGTransformList newList; 115 newList.parse(transform); 116 117 if (SVGAnimatedProperty* wrapper = SVGAnimatedProperty::lookupWrapper<SVGElement, SVGAnimatedTransformList>(m_contextElement.get(), transformPropertyInfo())) 118 static_cast<SVGAnimatedTransformList*>(wrapper)->detachListWrappers(newList.size()); 119 120 m_transform = newList; 121 } 122 123 String SVGViewSpec::transformString() const 124 { 125 return SVGPropertyTraits<SVGTransformList>::toString(m_transform); 126 } 127 128 String SVGViewSpec::viewBoxString() const 129 { 130 return SVGPropertyTraits<SVGRect>::toString(viewBoxBaseValue()); 131 } 132 133 String SVGViewSpec::preserveAspectRatioString() const 134 { 135 return SVGPropertyTraits<SVGPreserveAspectRatio>::toString(preserveAspectRatioBaseValue()); 136 } 137 138 SVGElement* SVGViewSpec::viewTarget() const 139 { 140 if (!m_contextElement) 141 return 0; 142 Element* element = m_contextElement.get()->treeScope().getElementById(m_viewTargetString); 143 if (!element || !element->isSVGElement()) 144 return 0; 145 return toSVGElement(element); 146 } 147 148 SVGTransformListPropertyTearOff* SVGViewSpec::transform() 149 { 150 if (!m_contextElement) 151 return 0; 152 // Return the animVal here, as its readonly by default - which is exactly what we want here. 153 return static_cast<SVGTransformListPropertyTearOff*>(static_pointer_cast<SVGAnimatedTransformList>(lookupOrCreateTransformWrapper(this))->animVal()); 154 } 155 156 PassRefPtr<SVGAnimatedRect> SVGViewSpec::viewBox() 157 { 158 if (!m_contextElement) 159 return 0; 160 return static_pointer_cast<SVGAnimatedRect>(lookupOrCreateViewBoxWrapper(this)); 161 } 162 163 PassRefPtr<SVGAnimatedPreserveAspectRatio> SVGViewSpec::preserveAspectRatio() 164 { 165 if (!m_contextElement) 166 return 0; 167 return static_pointer_cast<SVGAnimatedPreserveAspectRatio>(lookupOrCreatePreserveAspectRatioWrapper(this)); 168 } 169 170 PassRefPtr<SVGAnimatedProperty> SVGViewSpec::lookupOrCreateViewBoxWrapper(SVGViewSpec* ownerType) 171 { 172 ASSERT(ownerType); 173 ASSERT(ownerType->contextElement()); 174 return SVGAnimatedProperty::lookupOrCreateWrapper<SVGElement, SVGAnimatedRect, SVGRect>(ownerType->contextElement(), viewBoxPropertyInfo(), ownerType->m_viewBox); 175 } 176 177 PassRefPtr<SVGAnimatedProperty> SVGViewSpec::lookupOrCreatePreserveAspectRatioWrapper(SVGViewSpec* ownerType) 178 { 179 ASSERT(ownerType); 180 ASSERT(ownerType->contextElement()); 181 return SVGAnimatedProperty::lookupOrCreateWrapper<SVGElement, SVGAnimatedPreserveAspectRatio, SVGPreserveAspectRatio>(ownerType->contextElement(), preserveAspectRatioPropertyInfo(), ownerType->m_preserveAspectRatio); 182 } 183 184 PassRefPtr<SVGAnimatedProperty> SVGViewSpec::lookupOrCreateTransformWrapper(SVGViewSpec* ownerType) 185 { 186 ASSERT(ownerType); 187 ASSERT(ownerType->contextElement()); 188 return SVGAnimatedProperty::lookupOrCreateWrapper<SVGElement, SVGAnimatedTransformList, SVGTransformList>(ownerType->contextElement(), transformPropertyInfo(), ownerType->m_transform); 189 } 190 191 void SVGViewSpec::reset() 192 { 193 m_zoomAndPan = SVGZoomAndPanMagnify; 194 m_transform.clear(); 195 m_viewBox = SVGRect(); 196 m_preserveAspectRatio = SVGPreserveAspectRatio(); 197 m_viewTargetString = emptyString(); 198 } 199 200 static const LChar svgViewSpec[] = {'s', 'v', 'g', 'V', 'i', 'e', 'w'}; 201 static const LChar viewBoxSpec[] = {'v', 'i', 'e', 'w', 'B', 'o', 'x'}; 202 static const LChar preserveAspectRatioSpec[] = {'p', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'A', 's', 'p', 'e', 'c', 't', 'R', 'a', 't', 'i', 'o'}; 203 static const LChar transformSpec[] = {'t', 'r', 'a', 'n', 's', 'f', 'o', 'r', 'm'}; 204 static const LChar zoomAndPanSpec[] = {'z', 'o', 'o', 'm', 'A', 'n', 'd', 'P', 'a', 'n'}; 205 static const LChar viewTargetSpec[] = {'v', 'i', 'e', 'w', 'T', 'a', 'r', 'g', 'e', 't'}; 206 207 template<typename CharType> 208 bool SVGViewSpec::parseViewSpecInternal(const CharType* ptr, const CharType* end) 209 { 210 if (!skipString(ptr, end, svgViewSpec, WTF_ARRAY_LENGTH(svgViewSpec))) 211 return false; 212 213 if (ptr >= end || *ptr != '(') 214 return false; 215 ptr++; 216 217 while (ptr < end && *ptr != ')') { 218 if (*ptr == 'v') { 219 if (skipString(ptr, end, viewBoxSpec, WTF_ARRAY_LENGTH(viewBoxSpec))) { 220 if (ptr >= end || *ptr != '(') 221 return false; 222 ptr++; 223 SVGRect viewBox; 224 if (!SVGFitToViewBox::parseViewBox(&m_contextElement.get()->document(), ptr, end, viewBox, false)) 225 return false; 226 setViewBoxBaseValue(viewBox); 227 if (ptr >= end || *ptr != ')') 228 return false; 229 ptr++; 230 } else if (skipString(ptr, end, viewTargetSpec, WTF_ARRAY_LENGTH(viewTargetSpec))) { 231 if (ptr >= end || *ptr != '(') 232 return false; 233 const CharType* viewTargetStart = ++ptr; 234 while (ptr < end && *ptr != ')') 235 ptr++; 236 if (ptr >= end) 237 return false; 238 setViewTargetString(String(viewTargetStart, ptr - viewTargetStart)); 239 ptr++; 240 } else 241 return false; 242 } else if (*ptr == 'z') { 243 if (!skipString(ptr, end, zoomAndPanSpec, WTF_ARRAY_LENGTH(zoomAndPanSpec))) 244 return false; 245 if (ptr >= end || *ptr != '(') 246 return false; 247 ptr++; 248 if (!parseZoomAndPan(ptr, end, m_zoomAndPan)) 249 return false; 250 if (ptr >= end || *ptr != ')') 251 return false; 252 ptr++; 253 } else if (*ptr == 'p') { 254 if (!skipString(ptr, end, preserveAspectRatioSpec, WTF_ARRAY_LENGTH(preserveAspectRatioSpec))) 255 return false; 256 if (ptr >= end || *ptr != '(') 257 return false; 258 ptr++; 259 SVGPreserveAspectRatio preserveAspectRatio; 260 if (!preserveAspectRatio.parse(ptr, end, false)) 261 return false; 262 setPreserveAspectRatioBaseValue(preserveAspectRatio); 263 if (ptr >= end || *ptr != ')') 264 return false; 265 ptr++; 266 } else if (*ptr == 't') { 267 if (!skipString(ptr, end, transformSpec, WTF_ARRAY_LENGTH(transformSpec))) 268 return false; 269 if (ptr >= end || *ptr != '(') 270 return false; 271 ptr++; 272 parseTransformAttribute(m_transform, ptr, end, DoNotClearList); 273 if (ptr >= end || *ptr != ')') 274 return false; 275 ptr++; 276 } else 277 return false; 278 279 if (ptr < end && *ptr == ';') 280 ptr++; 281 } 282 283 if (ptr >= end || *ptr != ')') 284 return false; 285 286 return true; 287 } 288 289 bool SVGViewSpec::parseViewSpec(const String& spec) 290 { 291 if (spec.isEmpty() || !m_contextElement) 292 return false; 293 if (spec.is8Bit()) { 294 const LChar* ptr = spec.characters8(); 295 const LChar* end = ptr + spec.length(); 296 return parseViewSpecInternal(ptr, end); 297 } 298 const UChar* ptr = spec.characters16(); 299 const UChar* end = ptr + spec.length(); 300 return parseViewSpecInternal(ptr, end); 301 } 302 303 } 304