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