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 "bindings/v8/ExceptionMessages.h" 24 #include "bindings/v8/ExceptionState.h" 25 #include "core/SVGNames.h" 26 #include "core/dom/Document.h" 27 #include "core/dom/ExceptionCode.h" 28 #include "core/svg/SVGAnimatedTransformList.h" 29 #include "core/svg/SVGParserUtilities.h" 30 31 namespace WebCore { 32 33 SVGViewSpec::SVGViewSpec(SVGSVGElement* contextElement) 34 // Note: addToPropertyMap is not needed, as SVGViewSpec do not correspond to an element. 35 // Note: We make tear-offs' contextElement the target element of SVGViewSpec. 36 // This contextElement will be only used for keeping this alive from the tearoff. 37 // SVGSVGElement holds a strong-ref to this SVGViewSpec, so this is kept alive as: 38 // AnimatedProperty tearoff -(contextElement)-> SVGSVGElement -(RefPtr)-> SVGViewSpec. 39 : SVGFitToViewBox(contextElement, PropertyMapPolicySkip) 40 , m_contextElement(contextElement) 41 , m_transform(SVGAnimatedTransformList::create(contextElement, SVGNames::transformAttr, SVGTransformList::create())) 42 { 43 ASSERT(m_contextElement); 44 ScriptWrappable::init(this); 45 46 viewBox()->setReadOnly(); 47 preserveAspectRatio()->setReadOnly(); 48 m_transform->setReadOnly(); 49 // Note: addToPropertyMap is not needed, as SVGViewSpec do not correspond to an element. 50 } 51 52 bool SVGViewSpec::parseViewSpec(const String& spec) 53 { 54 if (spec.isEmpty() || !m_contextElement) 55 return false; 56 if (spec.is8Bit()) { 57 const LChar* ptr = spec.characters8(); 58 const LChar* end = ptr + spec.length(); 59 return parseViewSpecInternal(ptr, end); 60 } 61 const UChar* ptr = spec.characters16(); 62 const UChar* end = ptr + spec.length(); 63 return parseViewSpecInternal(ptr, end); 64 } 65 66 void SVGViewSpec::reset() 67 { 68 resetZoomAndPan(); 69 m_transform->baseValue()->clear(); 70 updateViewBox(FloatRect()); 71 ASSERT(preserveAspectRatio()); 72 preserveAspectRatio()->baseValue()->setAlign(SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID); 73 preserveAspectRatio()->baseValue()->setMeetOrSlice(SVGPreserveAspectRatio::SVG_MEETORSLICE_MEET); 74 m_viewTargetString = emptyString(); 75 } 76 77 void SVGViewSpec::detachContextElement() 78 { 79 m_transform = nullptr; 80 clearViewBox(); 81 clearPreserveAspectRatio(); 82 m_contextElement = nullptr; 83 } 84 85 SVGElement* SVGViewSpec::viewTarget() const 86 { 87 if (!m_contextElement) 88 return 0; 89 Element* element = m_contextElement->treeScope().getElementById(AtomicString(m_viewTargetString)); 90 if (!element || !element->isSVGElement()) 91 return 0; 92 return toSVGElement(element); 93 } 94 95 String SVGViewSpec::viewBoxString() const 96 { 97 if (!viewBox()) 98 return String(); 99 100 return viewBox()->currentValue()->valueAsString(); 101 } 102 103 String SVGViewSpec::preserveAspectRatioString() const 104 { 105 if (!preserveAspectRatio()) 106 return String(); 107 108 return preserveAspectRatio()->baseValue()->valueAsString(); 109 } 110 111 String SVGViewSpec::transformString() const 112 { 113 if (!m_transform) 114 return String(); 115 116 return m_transform->baseValue()->valueAsString(); 117 } 118 119 void SVGViewSpec::setZoomAndPan(unsigned short, ExceptionState& exceptionState) 120 { 121 // SVGViewSpec and all of its content is read-only. 122 exceptionState.throwDOMException(NoModificationAllowedError, ExceptionMessages::readOnly()); 123 } 124 125 static const LChar svgViewSpec[] = {'s', 'v', 'g', 'V', 'i', 'e', 'w'}; 126 static const LChar viewBoxSpec[] = {'v', 'i', 'e', 'w', 'B', 'o', 'x'}; 127 static const LChar preserveAspectRatioSpec[] = {'p', 'r', 'e', 's', 'e', 'r', 'v', 'e', 'A', 's', 'p', 'e', 'c', 't', 'R', 'a', 't', 'i', 'o'}; 128 static const LChar transformSpec[] = {'t', 'r', 'a', 'n', 's', 'f', 'o', 'r', 'm'}; 129 static const LChar zoomAndPanSpec[] = {'z', 'o', 'o', 'm', 'A', 'n', 'd', 'P', 'a', 'n'}; 130 static const LChar viewTargetSpec[] = {'v', 'i', 'e', 'w', 'T', 'a', 'r', 'g', 'e', 't'}; 131 132 template<typename CharType> 133 bool SVGViewSpec::parseViewSpecInternal(const CharType* ptr, const CharType* end) 134 { 135 if (!skipString(ptr, end, svgViewSpec, WTF_ARRAY_LENGTH(svgViewSpec))) 136 return false; 137 138 if (ptr >= end || *ptr != '(') 139 return false; 140 ptr++; 141 142 while (ptr < end && *ptr != ')') { 143 if (*ptr == 'v') { 144 if (skipString(ptr, end, viewBoxSpec, WTF_ARRAY_LENGTH(viewBoxSpec))) { 145 if (ptr >= end || *ptr != '(') 146 return false; 147 ptr++; 148 float x = 0.0f; 149 float y = 0.0f; 150 float width = 0.0f; 151 float height = 0.0f; 152 if (!(parseNumber(ptr, end, x) && parseNumber(ptr, end, y) && parseNumber(ptr, end, width) && parseNumber(ptr, end, height, DisallowWhitespace))) 153 return false; 154 updateViewBox(FloatRect(x, y, width, height)); 155 if (ptr >= end || *ptr != ')') 156 return false; 157 ptr++; 158 } else if (skipString(ptr, end, viewTargetSpec, WTF_ARRAY_LENGTH(viewTargetSpec))) { 159 if (ptr >= end || *ptr != '(') 160 return false; 161 const CharType* viewTargetStart = ++ptr; 162 while (ptr < end && *ptr != ')') 163 ptr++; 164 if (ptr >= end) 165 return false; 166 m_viewTargetString = String(viewTargetStart, ptr - viewTargetStart); 167 ptr++; 168 } else 169 return false; 170 } else if (*ptr == 'z') { 171 if (!skipString(ptr, end, zoomAndPanSpec, WTF_ARRAY_LENGTH(zoomAndPanSpec))) 172 return false; 173 if (ptr >= end || *ptr != '(') 174 return false; 175 ptr++; 176 if (!parseZoomAndPan(ptr, end)) 177 return false; 178 if (ptr >= end || *ptr != ')') 179 return false; 180 ptr++; 181 } else if (*ptr == 'p') { 182 if (!skipString(ptr, end, preserveAspectRatioSpec, WTF_ARRAY_LENGTH(preserveAspectRatioSpec))) 183 return false; 184 if (ptr >= end || *ptr != '(') 185 return false; 186 ptr++; 187 if (!preserveAspectRatio()->baseValue()->parse(ptr, end, false)) 188 return false; 189 if (ptr >= end || *ptr != ')') 190 return false; 191 ptr++; 192 } else if (*ptr == 't') { 193 if (!skipString(ptr, end, transformSpec, WTF_ARRAY_LENGTH(transformSpec))) 194 return false; 195 if (ptr >= end || *ptr != '(') 196 return false; 197 ptr++; 198 m_transform->baseValue()->parse(ptr, end); 199 if (ptr >= end || *ptr != ')') 200 return false; 201 ptr++; 202 } else 203 return false; 204 205 if (ptr < end && *ptr == ';') 206 ptr++; 207 } 208 209 if (ptr >= end || *ptr != ')') 210 return false; 211 212 return true; 213 } 214 215 void SVGViewSpec::trace(Visitor* visitor) 216 { 217 visitor->trace(m_contextElement); 218 } 219 220 } 221