/* Copyright (C) 2007 Krzysztof Kowalczyk Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann 2004, 2005, 2006 Rob Buis 2005, 2007 Apple Inc. All Rights reserved. 2007 Alp Toker This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License aint with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include "Path.h" #include "AffineTransform.h" #include "CairoPath.h" #include "FloatRect.h" #include "NotImplemented.h" #include "PlatformString.h" #include #include #include namespace WebCore { Path::Path() : m_path(new CairoPath()) { } Path::~Path() { delete m_path; } Path::Path(const Path& other) : m_path(new CairoPath()) { cairo_t* cr = platformPath()->m_cr; cairo_path_t* p = cairo_copy_path(other.platformPath()->m_cr); cairo_append_path(cr, p); cairo_path_destroy(p); } Path& Path::operator=(const Path& other) { if (&other == this) return *this; clear(); cairo_t* cr = platformPath()->m_cr; cairo_path_t* p = cairo_copy_path(other.platformPath()->m_cr); cairo_append_path(cr, p); cairo_path_destroy(p); return *this; } void Path::clear() { cairo_t* cr = platformPath()->m_cr; cairo_new_path(cr); } bool Path::isEmpty() const { // FIXME: if/when the patch to get current pt return status is applied // double dx,dy; // return cairo_get_current_point(cr, &dx, &dy); cairo_t* cr = platformPath()->m_cr; cairo_path_t* p = cairo_copy_path(platformPath()->m_cr); bool hasData = p->num_data; cairo_path_destroy(p); return !hasData; } void Path::translate(const FloatSize& p) { cairo_t* cr = platformPath()->m_cr; cairo_translate(cr, p.width(), p.height()); } void Path::moveTo(const FloatPoint& p) { cairo_t* cr = platformPath()->m_cr; cairo_move_to(cr, p.x(), p.y()); } void Path::addLineTo(const FloatPoint& p) { cairo_t* cr = platformPath()->m_cr; cairo_line_to(cr, p.x(), p.y()); } void Path::addRect(const FloatRect& rect) { cairo_t* cr = platformPath()->m_cr; cairo_rectangle(cr, rect.x(), rect.y(), rect.width(), rect.height()); } /* * inspired by libsvg-cairo */ void Path::addQuadCurveTo(const FloatPoint& controlPoint, const FloatPoint& point) { cairo_t* cr = platformPath()->m_cr; double x, y; double x1 = controlPoint.x(); double y1 = controlPoint.y(); double x2 = point.x(); double y2 = point.y(); cairo_get_current_point(cr, &x, &y); cairo_curve_to(cr, x + 2.0 / 3.0 * (x1 - x), y + 2.0 / 3.0 * (y1 - y), x2 + 2.0 / 3.0 * (x1 - x2), y2 + 2.0 / 3.0 * (y1 - y2), x2, y2); } void Path::addBezierCurveTo(const FloatPoint& controlPoint1, const FloatPoint& controlPoint2, const FloatPoint& controlPoint3) { cairo_t* cr = platformPath()->m_cr; cairo_curve_to(cr, controlPoint1.x(), controlPoint1.y(), controlPoint2.x(), controlPoint2.y(), controlPoint3.x(), controlPoint3.y()); } void Path::addArc(const FloatPoint& p, float r, float sa, float ea, bool clockwise) { cairo_t* cr = platformPath()->m_cr; if (clockwise) cairo_arc(cr, p.x(), p.y(), r, sa, ea); else cairo_arc_negative(cr, p.x(), p.y(), r, sa, ea); } void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius) { // FIXME: cairo_arc_to not yet in cairo see cairo.h // cairo_arc_to(m_cr, p1.x(), p1.y(), p2.x(), p2.y()); notImplemented(); } void Path::addEllipse(const FloatRect& rect) { cairo_t* cr = platformPath()->m_cr; cairo_save(cr); float yRadius = .5 * rect.height(); float xRadius = .5 * rect.width(); cairo_translate(cr, rect.x() + xRadius, rect.y() + yRadius); cairo_scale(cr, xRadius, yRadius); cairo_arc(cr, 0., 0., 1., 0., 2 * M_PI); cairo_restore(cr); } void Path::closeSubpath() { cairo_t* cr = platformPath()->m_cr; cairo_close_path(cr); } FloatRect Path::boundingRect() const { cairo_t* cr = platformPath()->m_cr; double x0, x1, y0, y1; cairo_fill_extents(cr, &x0, &y0, &x1, &y1); return FloatRect(x0, y0, x1 - x0, y1 - y0); } bool Path::contains(const FloatPoint& point, WindRule rule) const { cairo_t* cr = platformPath()->m_cr; cairo_fill_rule_t cur = cairo_get_fill_rule(cr); cairo_set_fill_rule(cr, rule == RULE_EVENODD ? CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING); bool contains = cairo_in_fill(cr, point.x(), point.y()); cairo_set_fill_rule(cr, cur); return contains; } void Path::apply(void* info, PathApplierFunction function) const { cairo_t* cr = platformPath()->m_cr; cairo_path_t* path = cairo_copy_path(cr); cairo_path_data_t* data; PathElement pelement; FloatPoint points[3]; pelement.points = points; for (int i = 0; i < path->num_data; i += path->data[i].header.length) { data = &path->data[i]; switch (data->header.type) { case CAIRO_PATH_MOVE_TO: pelement.type = PathElementMoveToPoint; pelement.points[0] = FloatPoint(data[1].point.x,data[1].point.y); function(info, &pelement); break; case CAIRO_PATH_LINE_TO: pelement.type = PathElementAddLineToPoint; pelement.points[0] = FloatPoint(data[1].point.x,data[1].point.y); function(info, &pelement); break; case CAIRO_PATH_CURVE_TO: pelement.type = PathElementAddCurveToPoint; pelement.points[0] = FloatPoint(data[1].point.x,data[1].point.y); pelement.points[1] = FloatPoint(data[2].point.x,data[2].point.y); pelement.points[2] = FloatPoint(data[3].point.x,data[3].point.y); function(info, &pelement); break; case CAIRO_PATH_CLOSE_PATH: pelement.type = PathElementCloseSubpath; function(info, &pelement); break; } } cairo_path_destroy(path); } void Path::transform(const AffineTransform& trans) { cairo_t* m_cr = platformPath()->m_cr; cairo_matrix_t c_matrix = cairo_matrix_t(trans); cairo_transform(m_cr, &c_matrix); } String Path::debugString() const { String string = ""; cairo_path_t* path = cairo_copy_path(platformPath()->m_cr); cairo_path_data_t* data; if (!path->num_data ) string = "EMPTY"; for (int i = 0; i < path->num_data; i += path->data[i].header.length) { data = &path->data[i]; switch (data->header.type) { case CAIRO_PATH_MOVE_TO: string += String::format("M %.2f,%.2f", data[1].point.x, data[1].point.y); break; case CAIRO_PATH_LINE_TO: string += String::format("L %.2f,%.2f", data[1].point.x, data[1].point.y); break; case CAIRO_PATH_CURVE_TO: string += String::format("C %.2f,%.2f,%.2f,%.2f,%.2f,%.2f", data[1].point.x, data[1].point.y, data[2].point.x, data[2].point.y, data[3].point.x, data[3].point.y); break; case CAIRO_PATH_CLOSE_PATH: string += "X"; break; } } cairo_path_destroy(path); return string; } } // namespace WebCore