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