Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) Research In Motion Limited 2010. 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 #ifndef SVGMarkerData_h
     21 #define SVGMarkerData_h
     22 
     23 #include "core/platform/FloatConversion.h"
     24 #include "core/platform/graphics/Path.h"
     25 #include "wtf/MathExtras.h"
     26 
     27 namespace WebCore {
     28 
     29 class RenderSVGResourceMarker;
     30 
     31 enum SVGMarkerType {
     32     StartMarker,
     33     MidMarker,
     34     EndMarker
     35 };
     36 
     37 struct MarkerPosition {
     38     MarkerPosition(SVGMarkerType useType, const FloatPoint& useOrigin, float useAngle)
     39         : type(useType)
     40         , origin(useOrigin)
     41         , angle(useAngle)
     42     {
     43     }
     44 
     45     SVGMarkerType type;
     46     FloatPoint origin;
     47     float angle;
     48 };
     49 
     50 class SVGMarkerData {
     51 public:
     52     SVGMarkerData(Vector<MarkerPosition>& positions)
     53         : m_positions(positions)
     54         , m_elementIndex(0)
     55     {
     56     }
     57 
     58     static void updateFromPathElement(void* info, const PathElement* element)
     59     {
     60         SVGMarkerData* markerData = static_cast<SVGMarkerData*>(info);
     61 
     62         // First update the outslope for the previous element.
     63         markerData->updateOutslope(element->points[0]);
     64 
     65         // Record the marker for the previous element.
     66         if (markerData->m_elementIndex > 0) {
     67             SVGMarkerType markerType = markerData->m_elementIndex == 1 ? StartMarker : MidMarker;
     68             markerData->m_positions.append(MarkerPosition(markerType, markerData->m_origin, markerData->currentAngle(markerType)));
     69         }
     70 
     71         // Update our marker data for this element.
     72         markerData->updateMarkerDataForPathElement(element);
     73         ++markerData->m_elementIndex;
     74     }
     75 
     76     void pathIsDone()
     77     {
     78         m_positions.append(MarkerPosition(EndMarker, m_origin, currentAngle(EndMarker)));
     79     }
     80 
     81 private:
     82     float currentAngle(SVGMarkerType type) const
     83     {
     84         // For details of this calculation, see: http://www.w3.org/TR/SVG/single-page.html#painting-MarkerElement
     85         FloatPoint inSlope(m_inslopePoints[1] - m_inslopePoints[0]);
     86         FloatPoint outSlope(m_outslopePoints[1] - m_outslopePoints[0]);
     87 
     88         double inAngle = rad2deg(inSlope.slopeAngleRadians());
     89         double outAngle = rad2deg(outSlope.slopeAngleRadians());
     90 
     91         switch (type) {
     92         case StartMarker:
     93             return narrowPrecisionToFloat(outAngle);
     94         case MidMarker:
     95             // WK193015: Prevent bugs due to angles being non-continuous.
     96             if (fabs(inAngle - outAngle) > 180)
     97                 inAngle += 360;
     98             return narrowPrecisionToFloat((inAngle + outAngle) / 2);
     99         case EndMarker:
    100             return narrowPrecisionToFloat(inAngle);
    101         }
    102 
    103         ASSERT_NOT_REACHED();
    104         return 0;
    105     }
    106 
    107     void updateOutslope(const FloatPoint& point)
    108     {
    109         m_outslopePoints[0] = m_origin;
    110         m_outslopePoints[1] = point;
    111     }
    112 
    113     void updateMarkerDataForPathElement(const PathElement* element)
    114     {
    115         FloatPoint* points = element->points;
    116 
    117         switch (element->type) {
    118         case PathElementAddQuadCurveToPoint:
    119             // FIXME: https://bugs.webkit.org/show_bug.cgi?id=33115 (PathElementAddQuadCurveToPoint not handled for <marker>)
    120             m_origin = points[1];
    121             break;
    122         case PathElementAddCurveToPoint:
    123             m_inslopePoints[0] = points[1];
    124             m_inslopePoints[1] = points[2];
    125             m_origin = points[2];
    126             break;
    127         case PathElementMoveToPoint:
    128             m_subpathStart = points[0];
    129         case PathElementAddLineToPoint:
    130             updateInslope(points[0]);
    131             m_origin = points[0];
    132             break;
    133         case PathElementCloseSubpath:
    134             updateInslope(points[0]);
    135             m_origin = m_subpathStart;
    136             m_subpathStart = FloatPoint();
    137         }
    138     }
    139 
    140     void updateInslope(const FloatPoint& point)
    141     {
    142         m_inslopePoints[0] = m_origin;
    143         m_inslopePoints[1] = point;
    144     }
    145 
    146     Vector<MarkerPosition>& m_positions;
    147     unsigned m_elementIndex;
    148     FloatPoint m_origin;
    149     FloatPoint m_subpathStart;
    150     FloatPoint m_inslopePoints[2];
    151     FloatPoint m_outslopePoints[2];
    152 };
    153 
    154 }
    155 
    156 #endif // SVGMarkerData_h
    157