Home | History | Annotate | Download | only in svg
      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