Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
      3  * Copyright (C) 2013 Apple Inc. All rights reserved.
      4  *
      5  * This library is free software; you can redistribute it and/or
      6  * modify it under the terms of the GNU Library General Public
      7  * License as published by the Free Software Foundation; either
      8  * version 2 of the License, or (at your option) any later version.
      9  *
     10  * This library is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  * Library General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU Library General Public License
     16  * along with this library; see the file COPYING.LIB.  If not, write to
     17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18  * Boston, MA 02110-1301, USA.
     19  */
     20 
     21 #include "config.h"
     22 
     23 #include "core/svg/SVGPathStringSource.h"
     24 
     25 #include "core/platform/graphics/FloatPoint.h"
     26 #include "core/svg/SVGParserUtilities.h"
     27 
     28 namespace WebCore {
     29 
     30 SVGPathStringSource::SVGPathStringSource(const String& string)
     31     : m_string(string)
     32     , m_is8BitSource(string.is8Bit())
     33 {
     34     ASSERT(!string.isEmpty());
     35 
     36     if (m_is8BitSource) {
     37         m_current.m_character8 = string.characters8();
     38         m_end.m_character8 = m_current.m_character8 + string.length();
     39     } else {
     40         m_current.m_character16 = string.characters16();
     41         m_end.m_character16 = m_current.m_character16 + string.length();
     42     }
     43 }
     44 
     45 bool SVGPathStringSource::hasMoreData() const
     46 {
     47     if (m_is8BitSource)
     48         return m_current.m_character8 < m_end.m_character8;
     49     return m_current.m_character16 < m_end.m_character16;
     50 }
     51 
     52 bool SVGPathStringSource::moveToNextToken()
     53 {
     54     if (m_is8BitSource)
     55         return skipOptionalSVGSpaces(m_current.m_character8, m_end.m_character8);
     56     return skipOptionalSVGSpaces(m_current.m_character16, m_end.m_character16);
     57 }
     58 
     59 template <typename CharacterType>
     60 static bool parseSVGSegmentTypeHelper(const CharacterType*& current, SVGPathSegType& pathSegType)
     61 {
     62     switch (*(current++)) {
     63     case 'Z':
     64     case 'z':
     65         pathSegType = PathSegClosePath;
     66         break;
     67     case 'M':
     68         pathSegType = PathSegMoveToAbs;
     69         break;
     70     case 'm':
     71         pathSegType = PathSegMoveToRel;
     72         break;
     73     case 'L':
     74         pathSegType = PathSegLineToAbs;
     75         break;
     76     case 'l':
     77         pathSegType = PathSegLineToRel;
     78         break;
     79     case 'C':
     80         pathSegType = PathSegCurveToCubicAbs;
     81         break;
     82     case 'c':
     83         pathSegType = PathSegCurveToCubicRel;
     84         break;
     85     case 'Q':
     86         pathSegType = PathSegCurveToQuadraticAbs;
     87         break;
     88     case 'q':
     89         pathSegType = PathSegCurveToQuadraticRel;
     90         break;
     91     case 'A':
     92         pathSegType = PathSegArcAbs;
     93         break;
     94     case 'a':
     95         pathSegType = PathSegArcRel;
     96         break;
     97     case 'H':
     98         pathSegType = PathSegLineToHorizontalAbs;
     99         break;
    100     case 'h':
    101         pathSegType = PathSegLineToHorizontalRel;
    102         break;
    103     case 'V':
    104         pathSegType = PathSegLineToVerticalAbs;
    105         break;
    106     case 'v':
    107         pathSegType = PathSegLineToVerticalRel;
    108         break;
    109     case 'S':
    110         pathSegType = PathSegCurveToCubicSmoothAbs;
    111         break;
    112     case 's':
    113         pathSegType = PathSegCurveToCubicSmoothRel;
    114         break;
    115     case 'T':
    116         pathSegType = PathSegCurveToQuadraticSmoothAbs;
    117         break;
    118     case 't':
    119         pathSegType = PathSegCurveToQuadraticSmoothRel;
    120         break;
    121     default:
    122         pathSegType = PathSegUnknown;
    123     }
    124     return true;
    125 }
    126 
    127 bool SVGPathStringSource::parseSVGSegmentType(SVGPathSegType& pathSegType)
    128 {
    129     if (m_is8BitSource)
    130         return parseSVGSegmentTypeHelper(m_current.m_character8, pathSegType);
    131     return parseSVGSegmentTypeHelper(m_current.m_character16, pathSegType);
    132 }
    133 
    134 template <typename CharacterType>
    135 static bool nextCommandHelper(const CharacterType*& current, SVGPathSegType previousCommand, SVGPathSegType& nextCommand)
    136 {
    137     // Check for remaining coordinates in the current command.
    138     if ((*current == '+' || *current == '-' || *current == '.' || (*current >= '0' && *current <= '9'))
    139         && previousCommand != PathSegClosePath) {
    140         if (previousCommand == PathSegMoveToAbs) {
    141             nextCommand = PathSegLineToAbs;
    142             return true;
    143         }
    144         if (previousCommand == PathSegMoveToRel) {
    145             nextCommand = PathSegLineToRel;
    146             return true;
    147         }
    148         nextCommand = previousCommand;
    149         return true;
    150     }
    151 
    152     return false;
    153 }
    154 
    155 SVGPathSegType SVGPathStringSource::nextCommand(SVGPathSegType previousCommand)
    156 {
    157     SVGPathSegType nextCommand;
    158     if (m_is8BitSource) {
    159         if (nextCommandHelper(m_current.m_character8, previousCommand, nextCommand))
    160             return nextCommand;
    161     } else {
    162         if (nextCommandHelper(m_current.m_character16, previousCommand, nextCommand))
    163             return nextCommand;
    164     }
    165 
    166     parseSVGSegmentType(nextCommand);
    167     return nextCommand;
    168 }
    169 
    170 bool SVGPathStringSource::parseMoveToSegment(FloatPoint& targetPoint)
    171 {
    172     if (m_is8BitSource)
    173         return parseFloatPoint(m_current.m_character8, m_end.m_character8, targetPoint);
    174     return parseFloatPoint(m_current.m_character16, m_end.m_character16, targetPoint);
    175 }
    176 
    177 bool SVGPathStringSource::parseLineToSegment(FloatPoint& targetPoint)
    178 {
    179     if (m_is8BitSource)
    180         return parseFloatPoint(m_current.m_character8, m_end.m_character8, targetPoint);
    181     return parseFloatPoint(m_current.m_character16, m_end.m_character16, targetPoint);
    182 }
    183 
    184 bool SVGPathStringSource::parseLineToHorizontalSegment(float& x)
    185 {
    186     if (m_is8BitSource)
    187         return parseNumber(m_current.m_character8, m_end.m_character8, x);
    188     return parseNumber(m_current.m_character16, m_end.m_character16, x);
    189 }
    190 
    191 bool SVGPathStringSource::parseLineToVerticalSegment(float& y)
    192 {
    193     if (m_is8BitSource)
    194         return parseNumber(m_current.m_character8, m_end.m_character8, y);
    195     return parseNumber(m_current.m_character16, m_end.m_character16, y);
    196 }
    197 
    198 bool SVGPathStringSource::parseCurveToCubicSegment(FloatPoint& point1, FloatPoint& point2, FloatPoint& targetPoint)
    199 {
    200     if (m_is8BitSource)
    201         return parseFloatPoint3(m_current.m_character8, m_end.m_character8, point1, point2, targetPoint);
    202     return parseFloatPoint3(m_current.m_character16, m_end.m_character16, point1, point2, targetPoint);
    203 }
    204 
    205 bool SVGPathStringSource::parseCurveToCubicSmoothSegment(FloatPoint& point1, FloatPoint& targetPoint)
    206 {
    207     if (m_is8BitSource)
    208         return parseFloatPoint2(m_current.m_character8, m_end.m_character8, point1, targetPoint);
    209     return parseFloatPoint2(m_current.m_character16, m_end.m_character16, point1, targetPoint);
    210 }
    211 
    212 bool SVGPathStringSource::parseCurveToQuadraticSegment(FloatPoint& point2, FloatPoint& targetPoint)
    213 {
    214     if (m_is8BitSource)
    215         return parseFloatPoint2(m_current.m_character8, m_end.m_character8, point2, targetPoint);
    216     return parseFloatPoint2(m_current.m_character16, m_end.m_character16, point2, targetPoint);
    217 }
    218 
    219 bool SVGPathStringSource::parseCurveToQuadraticSmoothSegment(FloatPoint& targetPoint)
    220 {
    221     if (m_is8BitSource)
    222         return parseFloatPoint(m_current.m_character8, m_end.m_character8, targetPoint);
    223     return parseFloatPoint(m_current.m_character16, m_end.m_character16, targetPoint);
    224 }
    225 
    226 template <typename CharacterType>
    227 static bool parseArcToSegmentHelper(const CharacterType*& current, const CharacterType* end, float& rx, float& ry, float& angle, bool& largeArc, bool& sweep, FloatPoint& targetPoint)
    228 {
    229     float toX;
    230     float toY;
    231     if (!parseNumber(current, end, rx)
    232         || !parseNumber(current, end, ry)
    233         || !parseNumber(current, end, angle)
    234         || !parseArcFlag(current, end, largeArc)
    235         || !parseArcFlag(current, end, sweep)
    236         || !parseNumber(current, end, toX)
    237         || !parseNumber(current, end, toY))
    238         return false;
    239     targetPoint = FloatPoint(toX, toY);
    240     return true;
    241 }
    242 
    243 bool SVGPathStringSource::parseArcToSegment(float& rx, float& ry, float& angle, bool& largeArc, bool& sweep, FloatPoint& targetPoint)
    244 {
    245     if (m_is8BitSource)
    246         return parseArcToSegmentHelper(m_current.m_character8, m_end.m_character8, rx, ry, angle, largeArc, sweep, targetPoint);
    247     return parseArcToSegmentHelper(m_current.m_character16, m_end.m_character16, rx, ry, angle, largeArc, sweep, targetPoint);
    248 }
    249 
    250 } // namespace WebKit
    251