Home | History | Annotate | Download | only in skia
      1 // Copyright (c) 2008, Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 #include "config.h"
     31 #include "Path.h"
     32 
     33 #include "AffineTransform.h"
     34 #include "FloatRect.h"
     35 #include "ImageBuffer.h"
     36 #include "StrokeStyleApplier.h"
     37 
     38 #include "SkPath.h"
     39 #include "SkRegion.h"
     40 #include "SkiaUtils.h"
     41 
     42 #include <wtf/MathExtras.h>
     43 
     44 namespace WebCore {
     45 
     46 Path::Path()
     47 {
     48     m_path = new SkPath;
     49 }
     50 
     51 Path::Path(const Path& other)
     52 {
     53     m_path = new SkPath(*other.m_path);
     54 }
     55 
     56 Path::~Path()
     57 {
     58     delete m_path;
     59 }
     60 
     61 Path& Path::operator=(const Path& other)
     62 {
     63     *m_path = *other.m_path;
     64     return *this;
     65 }
     66 
     67 bool Path::isEmpty() const
     68 {
     69     return m_path->isEmpty();
     70 }
     71 
     72 bool Path::hasCurrentPoint() const
     73 {
     74     return m_path->getPoints(NULL, 0) != 0;
     75 }
     76 
     77 FloatPoint Path::currentPoint() const
     78 {
     79     // FIXME: return current point of subpath.
     80     float quietNaN = std::numeric_limits<float>::quiet_NaN();
     81     return FloatPoint(quietNaN, quietNaN);
     82 }
     83 
     84 bool Path::contains(const FloatPoint& point, WindRule rule) const
     85 {
     86     return SkPathContainsPoint(m_path, point,
     87       rule == RULE_NONZERO ? SkPath::kWinding_FillType : SkPath::kEvenOdd_FillType);
     88 }
     89 
     90 void Path::translate(const FloatSize& size)
     91 {
     92     m_path->offset(WebCoreFloatToSkScalar(size.width()), WebCoreFloatToSkScalar(size.height()));
     93 }
     94 
     95 FloatRect Path::boundingRect() const
     96 {
     97     return m_path->getBounds();
     98 }
     99 
    100 void Path::moveTo(const FloatPoint& point)
    101 {
    102     m_path->moveTo(point);
    103 }
    104 
    105 void Path::addLineTo(const FloatPoint& point)
    106 {
    107     m_path->lineTo(point);
    108 }
    109 
    110 void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& ep)
    111 {
    112     m_path->quadTo(cp, ep);
    113 }
    114 
    115 void Path::addBezierCurveTo(const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& ep)
    116 {
    117     m_path->cubicTo(p1, p2, ep);
    118 }
    119 
    120 void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
    121 {
    122     m_path->arcTo(p1, p2, WebCoreFloatToSkScalar(radius));
    123 }
    124 
    125 void Path::closeSubpath()
    126 {
    127     m_path->close();
    128 }
    129 
    130 void Path::addArc(const FloatPoint& p, float r, float sa, float ea, bool anticlockwise) {
    131     SkScalar cx = WebCoreFloatToSkScalar(p.x());
    132     SkScalar cy = WebCoreFloatToSkScalar(p.y());
    133     SkScalar radius = WebCoreFloatToSkScalar(r);
    134     SkScalar s360 = SkIntToScalar(360);
    135 
    136     SkRect oval;
    137     oval.set(cx - radius, cy - radius, cx + radius, cy + radius);
    138 
    139     float sweep = ea - sa;
    140     SkScalar startDegrees = WebCoreFloatToSkScalar(sa * 180 / piFloat);
    141     SkScalar sweepDegrees = WebCoreFloatToSkScalar(sweep * 180 / piFloat);
    142     // Check for a circle.
    143     if (sweepDegrees >= s360 || sweepDegrees <= -s360) {
    144         // Move to the start position (0 sweep means we add a single point).
    145         m_path->arcTo(oval, startDegrees, 0, false);
    146         // Draw the circle.
    147         m_path->addOval(oval, anticlockwise ?
    148             SkPath::kCCW_Direction : SkPath::kCW_Direction);
    149         // Force a moveTo the end position.
    150         m_path->arcTo(oval, startDegrees + sweepDegrees, 0, true);
    151     } else {
    152         // Counterclockwise arcs should be drawn with negative sweeps, while
    153         // clockwise arcs should be drawn with positive sweeps. Check to see
    154         // if the situation is reversed and correct it by adding or subtracting
    155         // a full circle
    156         if (anticlockwise && sweepDegrees > 0) {
    157             sweepDegrees -= s360;
    158         } else if (!anticlockwise && sweepDegrees < 0) {
    159             sweepDegrees += s360;
    160         }
    161 
    162         m_path->arcTo(oval, startDegrees, sweepDegrees, false);
    163     }
    164 }
    165 
    166 void Path::addRect(const FloatRect& rect)
    167 {
    168     m_path->addRect(rect);
    169 }
    170 
    171 void Path::addEllipse(const FloatRect& rect)
    172 {
    173     m_path->addOval(rect);
    174 }
    175 
    176 void Path::clear()
    177 {
    178     m_path->reset();
    179 }
    180 
    181 static FloatPoint* convertPathPoints(FloatPoint dst[], const SkPoint src[], int count)
    182 {
    183     for (int i = 0; i < count; i++) {
    184         dst[i].setX(SkScalarToFloat(src[i].fX));
    185         dst[i].setY(SkScalarToFloat(src[i].fY));
    186     }
    187     return dst;
    188 }
    189 
    190 void Path::apply(void* info, PathApplierFunction function) const
    191 {
    192     SkPath::Iter iter(*m_path, false);
    193     SkPoint pts[4];
    194     PathElement pathElement;
    195     FloatPoint pathPoints[3];
    196 
    197     for (;;) {
    198         switch (iter.next(pts)) {
    199         case SkPath::kMove_Verb:
    200             pathElement.type = PathElementMoveToPoint;
    201             pathElement.points = convertPathPoints(pathPoints, &pts[0], 1);
    202             break;
    203         case SkPath::kLine_Verb:
    204             pathElement.type = PathElementAddLineToPoint;
    205             pathElement.points = convertPathPoints(pathPoints, &pts[1], 1);
    206             break;
    207         case SkPath::kQuad_Verb:
    208             pathElement.type = PathElementAddQuadCurveToPoint;
    209             pathElement.points = convertPathPoints(pathPoints, &pts[1], 2);
    210             break;
    211         case SkPath::kCubic_Verb:
    212             pathElement.type = PathElementAddCurveToPoint;
    213             pathElement.points = convertPathPoints(pathPoints, &pts[1], 3);
    214             break;
    215         case SkPath::kClose_Verb:
    216             pathElement.type = PathElementCloseSubpath;
    217             pathElement.points = convertPathPoints(pathPoints, 0, 0);
    218             break;
    219         case SkPath::kDone_Verb:
    220             return;
    221         }
    222         function(info, &pathElement);
    223     }
    224 }
    225 
    226 void Path::transform(const AffineTransform& xform)
    227 {
    228     m_path->transform(xform);
    229 }
    230 
    231 FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) const
    232 {
    233     GraphicsContext* scratch = scratchContext();
    234     scratch->save();
    235 
    236     if (applier)
    237         applier->strokeStyle(scratch);
    238 
    239     SkPaint paint;
    240     scratch->platformContext()->setupPaintForStroking(&paint, 0, 0);
    241     SkPath boundingPath;
    242     paint.getFillPath(*platformPath(), &boundingPath);
    243 
    244     FloatRect r = boundingPath.getBounds();
    245     scratch->restore();
    246     return r;
    247 }
    248 
    249 bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const
    250 {
    251     ASSERT(applier);
    252     GraphicsContext* scratch = scratchContext();
    253     scratch->save();
    254 
    255     applier->strokeStyle(scratch);
    256 
    257     SkPaint paint;
    258     scratch->platformContext()->setupPaintForStroking(&paint, 0, 0);
    259     SkPath strokePath;
    260     paint.getFillPath(*platformPath(), &strokePath);
    261     bool contains = SkPathContainsPoint(&strokePath, point,
    262                                         SkPath::kWinding_FillType);
    263 
    264     scratch->restore();
    265     return contains;
    266 }
    267 } // namespace WebCore
    268