Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) Research In Motion Limited 2011. All rights reserved.
      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/rendering/svg/SVGPathData.h"
     22 
     23 #include "SVGNames.h"
     24 #include "core/svg/SVGCircleElement.h"
     25 #include "core/svg/SVGEllipseElement.h"
     26 #include "core/svg/SVGLineElement.h"
     27 #include "core/svg/SVGPathElement.h"
     28 #include "core/svg/SVGPathUtilities.h"
     29 #include "core/svg/SVGPolygonElement.h"
     30 #include "core/svg/SVGPolylineElement.h"
     31 #include "core/svg/SVGRectElement.h"
     32 #include "platform/graphics/Path.h"
     33 #include "wtf/HashMap.h"
     34 
     35 namespace WebCore {
     36 
     37 static void updatePathFromCircleElement(SVGElement* element, Path& path)
     38 {
     39     SVGCircleElement* circle = toSVGCircleElement(element);
     40 
     41     SVGLengthContext lengthContext(element);
     42     float r = circle->rCurrentValue().value(lengthContext);
     43     if (r > 0)
     44         path.addEllipse(FloatRect(circle->cxCurrentValue().value(lengthContext) - r, circle->cyCurrentValue().value(lengthContext) - r, r * 2, r * 2));
     45 }
     46 
     47 static void updatePathFromEllipseElement(SVGElement* element, Path& path)
     48 {
     49     SVGEllipseElement* ellipse = toSVGEllipseElement(element);
     50 
     51     SVGLengthContext lengthContext(element);
     52     float rx = ellipse->rxCurrentValue().value(lengthContext);
     53     if (rx <= 0)
     54         return;
     55     float ry = ellipse->ryCurrentValue().value(lengthContext);
     56     if (ry <= 0)
     57         return;
     58     path.addEllipse(FloatRect(ellipse->cxCurrentValue().value(lengthContext) - rx, ellipse->cyCurrentValue().value(lengthContext) - ry, rx * 2, ry * 2));
     59 }
     60 
     61 static void updatePathFromLineElement(SVGElement* element, Path& path)
     62 {
     63     SVGLineElement* line = toSVGLineElement(element);
     64 
     65     SVGLengthContext lengthContext(element);
     66     path.moveTo(FloatPoint(line->x1CurrentValue().value(lengthContext), line->y1CurrentValue().value(lengthContext)));
     67     path.addLineTo(FloatPoint(line->x2CurrentValue().value(lengthContext), line->y2CurrentValue().value(lengthContext)));
     68 }
     69 
     70 static void updatePathFromPathElement(SVGElement* element, Path& path)
     71 {
     72     buildPathFromByteStream(toSVGPathElement(element)->pathByteStream(), path);
     73 }
     74 
     75 static void updatePathFromPolygonElement(SVGElement* element, Path& path)
     76 {
     77     SVGPointList& points = toSVGPolygonElement(element)->pointsCurrentValue();
     78     if (points.isEmpty())
     79         return;
     80 
     81     path.moveTo(points.first());
     82 
     83     unsigned size = points.size();
     84     for (unsigned i = 1; i < size; ++i)
     85         path.addLineTo(points.at(i));
     86 
     87     path.closeSubpath();
     88 }
     89 
     90 static void updatePathFromPolylineElement(SVGElement* element, Path& path)
     91 {
     92     SVGPointList& points = toSVGPolylineElement(element)->pointsCurrentValue();
     93     if (points.isEmpty())
     94         return;
     95 
     96     path.moveTo(points.first());
     97 
     98     unsigned size = points.size();
     99     for (unsigned i = 1; i < size; ++i)
    100         path.addLineTo(points.at(i));
    101 }
    102 
    103 static void updatePathFromRectElement(SVGElement* element, Path& path)
    104 {
    105     SVGRectElement* rect = toSVGRectElement(element);
    106 
    107     SVGLengthContext lengthContext(element);
    108     float width = rect->widthCurrentValue().value(lengthContext);
    109     if (width <= 0)
    110         return;
    111     float height = rect->heightCurrentValue().value(lengthContext);
    112     if (height <= 0)
    113         return;
    114     float x = rect->xCurrentValue().value(lengthContext);
    115     float y = rect->yCurrentValue().value(lengthContext);
    116     bool hasRx = rect->rxCurrentValue().value(lengthContext) > 0;
    117     bool hasRy = rect->ryCurrentValue().value(lengthContext) > 0;
    118     if (hasRx || hasRy) {
    119         float rx = rect->rxCurrentValue().value(lengthContext);
    120         float ry = rect->ryCurrentValue().value(lengthContext);
    121         if (!hasRx)
    122             rx = ry;
    123         else if (!hasRy)
    124             ry = rx;
    125 
    126         path.addRoundedRect(FloatRect(x, y, width, height), FloatSize(rx, ry));
    127         return;
    128     }
    129 
    130     path.addRect(FloatRect(x, y, width, height));
    131 }
    132 
    133 void updatePathFromGraphicsElement(SVGElement* element, Path& path)
    134 {
    135     ASSERT(element);
    136     ASSERT(path.isEmpty());
    137 
    138     typedef void (*PathUpdateFunction)(SVGElement*, Path&);
    139     static HashMap<StringImpl*, PathUpdateFunction>* map = 0;
    140     if (!map) {
    141         map = new HashMap<StringImpl*, PathUpdateFunction>;
    142         map->set(SVGNames::circleTag.localName().impl(), updatePathFromCircleElement);
    143         map->set(SVGNames::ellipseTag.localName().impl(), updatePathFromEllipseElement);
    144         map->set(SVGNames::lineTag.localName().impl(), updatePathFromLineElement);
    145         map->set(SVGNames::pathTag.localName().impl(), updatePathFromPathElement);
    146         map->set(SVGNames::polygonTag.localName().impl(), updatePathFromPolygonElement);
    147         map->set(SVGNames::polylineTag.localName().impl(), updatePathFromPolylineElement);
    148         map->set(SVGNames::rectTag.localName().impl(), updatePathFromRectElement);
    149     }
    150 
    151     if (PathUpdateFunction pathUpdateFunction = map->get(element->localName().impl()))
    152         (*pathUpdateFunction)(element, path);
    153 }
    154 
    155 } // namespace WebCore
    156