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 "core/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 using namespace SVGNames;
     38 
     39 static void updatePathFromCircleElement(SVGElement* element, Path& path)
     40 {
     41     SVGCircleElement* circle = toSVGCircleElement(element);
     42 
     43     SVGLengthContext lengthContext(element);
     44     float r = circle->r()->currentValue()->value(lengthContext);
     45     if (r > 0)
     46         path.addEllipse(FloatRect(circle->cx()->currentValue()->value(lengthContext) - r, circle->cy()->currentValue()->value(lengthContext) - r, r * 2, r * 2));
     47 }
     48 
     49 static void updatePathFromEllipseElement(SVGElement* element, Path& path)
     50 {
     51     SVGEllipseElement* ellipse = toSVGEllipseElement(element);
     52 
     53     SVGLengthContext lengthContext(element);
     54     float rx = ellipse->rx()->currentValue()->value(lengthContext);
     55     if (rx < 0)
     56         return;
     57     float ry = ellipse->ry()->currentValue()->value(lengthContext);
     58     if (ry < 0)
     59         return;
     60     if (!rx && !ry)
     61         return;
     62 
     63     path.addEllipse(FloatRect(ellipse->cx()->currentValue()->value(lengthContext) - rx, ellipse->cy()->currentValue()->value(lengthContext) - ry, rx * 2, ry * 2));
     64 }
     65 
     66 static void updatePathFromLineElement(SVGElement* element, Path& path)
     67 {
     68     SVGLineElement* line = toSVGLineElement(element);
     69 
     70     SVGLengthContext lengthContext(element);
     71     path.moveTo(FloatPoint(line->x1()->currentValue()->value(lengthContext), line->y1()->currentValue()->value(lengthContext)));
     72     path.addLineTo(FloatPoint(line->x2()->currentValue()->value(lengthContext), line->y2()->currentValue()->value(lengthContext)));
     73 }
     74 
     75 static void updatePathFromPathElement(SVGElement* element, Path& path)
     76 {
     77     buildPathFromByteStream(toSVGPathElement(element)->pathByteStream(), path);
     78 }
     79 
     80 static void updatePathFromPolylineElement(SVGElement* element, Path& path)
     81 {
     82     RefPtr<SVGPointList> points = toSVGPolyElement(element)->points()->currentValue();
     83     if (points->isEmpty())
     84         return;
     85 
     86     SVGPointList::ConstIterator it = points->begin();
     87     SVGPointList::ConstIterator itEnd = points->end();
     88     ASSERT(it != itEnd);
     89     path.moveTo(it->value());
     90     ++it;
     91 
     92     for (; it != itEnd; ++it)
     93         path.addLineTo(it->value());
     94 }
     95 
     96 static void updatePathFromPolygonElement(SVGElement* element, Path& path)
     97 {
     98     updatePathFromPolylineElement(element, path);
     99     path.closeSubpath();
    100 }
    101 
    102 static void updatePathFromRectElement(SVGElement* element, Path& path)
    103 {
    104     SVGRectElement* rect = toSVGRectElement(element);
    105 
    106     SVGLengthContext lengthContext(element);
    107     float width = rect->width()->currentValue()->value(lengthContext);
    108     if (width < 0)
    109         return;
    110     float height = rect->height()->currentValue()->value(lengthContext);
    111     if (height < 0)
    112         return;
    113     if (!width && !height)
    114         return;
    115     float x = rect->x()->currentValue()->value(lengthContext);
    116     float y = rect->y()->currentValue()->value(lengthContext);
    117     float rx = rect->rx()->currentValue()->value(lengthContext);
    118     float ry = rect->ry()->currentValue()->value(lengthContext);
    119     bool hasRx = rx > 0;
    120     bool hasRy = ry > 0;
    121     if (hasRx || hasRy) {
    122         if (!hasRx)
    123             rx = ry;
    124         else if (!hasRy)
    125             ry = rx;
    126 
    127         path.addRoundedRect(FloatRect(x, y, width, height), FloatSize(rx, ry));
    128         return;
    129     }
    130 
    131     path.addRect(FloatRect(x, y, width, height));
    132 }
    133 
    134 void updatePathFromGraphicsElement(SVGElement* element, Path& path)
    135 {
    136     ASSERT(element);
    137     ASSERT(path.isEmpty());
    138 
    139     typedef void (*PathUpdateFunction)(SVGElement*, Path&);
    140     static HashMap<StringImpl*, PathUpdateFunction>* map = 0;
    141     if (!map) {
    142         map = new HashMap<StringImpl*, PathUpdateFunction>;
    143         map->set(circleTag.localName().impl(), updatePathFromCircleElement);
    144         map->set(ellipseTag.localName().impl(), updatePathFromEllipseElement);
    145         map->set(lineTag.localName().impl(), updatePathFromLineElement);
    146         map->set(pathTag.localName().impl(), updatePathFromPathElement);
    147         map->set(polygonTag.localName().impl(), updatePathFromPolygonElement);
    148         map->set(polylineTag.localName().impl(), updatePathFromPolylineElement);
    149         map->set(rectTag.localName().impl(), updatePathFromRectElement);
    150     }
    151 
    152     if (PathUpdateFunction pathUpdateFunction = map->get(element->localName().impl()))
    153         (*pathUpdateFunction)(element, path);
    154 }
    155 
    156 } // namespace WebCore
    157