From 115a4cc7c783904903cb1f0c23538527c9f7803d Mon Sep 17 00:00:00 2001 From: Povilas Kanapickas Date: Thu, 13 Feb 2014 02:10:11 +0200 Subject: [PATCH] Wrap mesh surface API --- cairomm/context.cc | 4 + cairomm/enums.h | 9 +- cairomm/filelist.am | 2 + cairomm/mesh_pattern.cc | 127 ++++++++++++++++ cairomm/mesh_pattern.h | 392 ++++++++++++++++++++++++++++++++++++++++++++++++ cairomm/path.cc | 9 +- cairomm/path.h | 20 ++- 7 files changed, 553 insertions(+), 10 deletions(-) create mode 100644 cairomm/mesh_pattern.cc create mode 100644 cairomm/mesh_pattern.h diff --git a/cairomm/context.cc b/cairomm/context.cc index c9d1411..4b58889 100644 --- a/cairomm/context.cc +++ b/cairomm/context.cc @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -691,6 +692,9 @@ static RefPtr get_pattern_wrapper (cairo_pattern_t* pattern) case CAIRO_PATTERN_TYPE_RADIAL: return RefPtr(new RadialGradient(pattern, false /* does not have reference */)); break; + case CAIRO_PATTERN_TYPE_MESH: + return RefPtr(new MeshPattern(pattern, false /* does not have reference */)); + break; default: return RefPtr(new Pattern(pattern, false /* does not have reference */)); } diff --git a/cairomm/enums.h b/cairomm/enums.h index 548a7f3..03f18a2 100644 --- a/cairomm/enums.h +++ b/cairomm/enums.h @@ -731,7 +731,14 @@ typedef enum /** * The pattern is a radial gradient. */ - PATTERN_TYPE_RADIAL = CAIRO_PATTERN_TYPE_RADIAL + PATTERN_TYPE_RADIAL = CAIRO_PATTERN_TYPE_RADIAL, + + /** + * The pattern is a mesh gradient. + * @since 1.12 + */ + PATTERN_TYPE_MESH = CAIRO_PATTERN_TYPE_MESH + } PatternType; diff --git a/cairomm/filelist.am b/cairomm/filelist.am index 53f1293..39cd6f0 100644 --- a/cairomm/filelist.am +++ b/cairomm/filelist.am @@ -10,6 +10,7 @@ cairomm_cc = \ fontface.cc \ fontoptions.cc \ matrix.cc \ + mesh_pattern.cc \ path.cc \ pattern.cc \ private.cc \ @@ -36,6 +37,7 @@ cairomm_public_h = \ fontface.h \ fontoptions.h \ matrix.h path.h \ + mesh_pattern.h \ pattern.h \ quartz_font.h \ quartz_surface.h \ diff --git a/cairomm/mesh_pattern.cc b/cairomm/mesh_pattern.cc new file mode 100644 index 0000000..35ee842 --- /dev/null +++ b/cairomm/mesh_pattern.cc @@ -0,0 +1,127 @@ +/* Copyright (C) 2014 The cairomm Development Team + * + * 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 along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include +#include + +namespace Cairo { + +MeshPattern::MeshPattern(cairo_pattern_t* cobject, bool has_reference) : + Pattern(cobject, has_reference) +{} + +MeshPattern::~MeshPattern() +{ + // pattern is destroyed in base class +} + +void MeshPattern::begin_patch() +{ + cairo_mesh_pattern_begin_patch(m_cobject); + check_status_and_throw_exception(cairo_pattern_status(m_cobject)); +} + +void MeshPattern::end_patch() +{ + cairo_mesh_pattern_end_patch(m_cobject); + check_status_and_throw_exception(cairo_pattern_status(m_cobject)); +} + + +void MeshPattern::move_to(double x, double y) +{ + cairo_mesh_pattern_move_to(m_cobject, x, y); + check_status_and_throw_exception(cairo_pattern_status(m_cobject)); +} + +void MeshPattern::line_to(double x, double y) +{ + cairo_mesh_pattern_line_to(m_cobject, x, y); + check_status_and_throw_exception(cairo_pattern_status(m_cobject)); +} + +void MeshPattern::curve_to(double x1, double y1, double x2, double y2, + double x3, double y3) +{ + cairo_mesh_pattern_curve_to(m_cobject, x1, y1, x2, y2, x3, y3); + check_status_and_throw_exception(cairo_pattern_status(m_cobject)); +} + +void MeshPattern::set_control_point(unsigned point_num, double x, double y) +{ + cairo_mesh_pattern_set_control_point(m_cobject, point_num, x, y); + check_status_and_throw_exception(cairo_pattern_status(m_cobject)); +} + + +void MeshPattern::set_corner_color_rgb(unsigned int corner_num, double red, + double green, double blue) +{ + cairo_mesh_pattern_set_corner_color_rgb(m_cobject, corner_num, red, green, + blue); + check_status_and_throw_exception(cairo_pattern_status(m_cobject)); +} + +void MeshPattern::set_corner_color_rgba(unsigned int corner_num, double red, + double green, double blue, double alpha) +{ + cairo_mesh_pattern_set_corner_color_rgba(m_cobject, corner_num, red, green, + blue, alpha); + check_status_and_throw_exception(cairo_pattern_status(m_cobject)); +} + +unsigned MeshPattern::get_patch_count() const +{ + unsigned res; + cairo_mesh_pattern_get_patch_count(m_cobject, &res); + return res; +} + +#if __cplusplus >= 201103L +Path MeshPattern::get_path(unsigned patch_num) const +{ + cairo_path_t* path = cairo_mesh_pattern_get_path(m_cobject, patch_num); + check_status_and_throw_exception(path->status); + return Path(path, true /* take owneship */); +} +#endif + +void MeshPattern::get_control_point(unsigned patch_num, unsigned point_num, + double& x, double& y) +{ + cairo_mesh_pattern_get_control_point(m_cobject, patch_num, point_num, &x, &y); + check_status_and_throw_exception(cairo_pattern_status(m_cobject)); +} + +void MeshPattern::get_corner_color_rgba(unsigned patch_num, unsigned corner_num, + double& red, double& green, double& blue, + double& alpha) +{ + cairo_mesh_pattern_get_corner_color_rgba(m_cobject, patch_num, corner_num, + &red, &green, &blue, &alpha); + check_status_and_throw_exception(cairo_pattern_status(m_cobject)); +} + +RefPtr MeshPattern::create() +{ + cairo_pattern_t* cobject = cairo_pattern_create_mesh(); + check_status_and_throw_exception(cairo_pattern_status(cobject)); + return RefPtr(new MeshPattern(cobject, true /* has reference */)); +} + +} //namespace Cairo diff --git a/cairomm/mesh_pattern.h b/cairomm/mesh_pattern.h new file mode 100644 index 0000000..024728b --- /dev/null +++ b/cairomm/mesh_pattern.h @@ -0,0 +1,392 @@ +/* Copyright (C) 2014 The cairomm Development Team + * + * 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 along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef __CAIROMM_MESH_PATTERN_H +#define __CAIROMM_MESH_PATTERN_H + +#include +#include +#include + +namespace Cairo { + +/** + * Mesh patterns are tensor-product patch meshes (type 7 shadings in PDF). Mesh + * patterns may also be used to create other types of shadings that are special + * cases of tensor-product patch meshes such as Coons patch meshes (type 6 + * shading in PDF) and Gouraud-shaded triangle meshes (type 4 and 5 shadings in + * PDF). + * + * Mesh patterns consist of one or more tensor-product patches, which should be + * defined before using the mesh pattern. Using a mesh pattern with a partially + * defined patch as source or mask will put the context in an error status with + * a status of CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. // TODO: exception + * + * A tensor-product patch is defined by 4 Bézier curves (side 0, 1, 2, 3) and + * by 4 additional control points (P0, P1, P2, P3) that provide further control + * over the patch and complete the definition of the tensor-product patch. The + * corner C0 is the first point of the patch. + * + * Degenerate sides are permitted so straight lines may be used. A zero length + * line on one side may be used to create 3 sided patches. + * + * + * C1 Side 1 C2 + * +---------------+ + * | | + * | P1 P2 | + * | | + * Side 0 | | Side 2 + * | | + * | | + * | P0 P3 | + * | | + * +---------------+ + * C0 Side 3 C3 + * + * Each patch is constructed by first calling @c MeshPattern::begin_patch(), + * then @c MeshPattern::move_to() to specify the first point in the patch + * (C0). Then the sides are specified with calls to + * @c MeshPattern::curve_to() and @c MeshPattern::line_to(). + * + * The four additional control points (P0, P1, P2, P3) in a patch can be + * specified with @c MeshPattern::set_control_point(). + * + * At each corner of the patch (C0, C1, C2, C3) a color may be specified with + * @c MeshPattern::set_corner_color_rgb() or @c + * MeshPattern::set_corner_color_rgba(). Any corner whose color is not + * explicitly specified defaults to transparent black. + * + * A Coons patch is a special case of the tensor-product patch where the + * control points are implicitly defined by the sides of the patch. The default + * value for any control point not specified is the implicit value for a Coons + * patch, i.e. if no control points are specified the patch is a Coons patch. + * + * A triangle is a special case of the tensor-product patch where the control + * points are implicitly defined by the sides of the patch, all the sides are + * lines and one of them has length 0, i.e. if the patch is specified using + * just 3 lines, it is a triangle. If the corners connected by the 0-length + * side have the same color, the patch is a Gouraud-shaded triangle. + * + * Patches may be oriented differently to the above diagram. For example the + * first point could be at the top left. The diagram only shows the + * relationship between the sides, corners and control points. Regardless of + * where the first point is located, when specifying colors, corner 0 will + * always be the first point, corner 1 the point between side 0 and side 1 etc. + * + * Calling cairo_mesh_pattern_end_patch() completes the current patch. If less + * than 4 sides have been defined, the first missing side is defined as a line + * from the current point to the first point of the patch (C0) and the other + * sides are degenerate lines from C0 to C0. The corners between the added + * sides will all be coincident with C0 of the patch and their color will be + * set to be the same as the color of C0. + * + * Additional patches may be added with additional calls to + * @c MeshPattern::begin_patch() and @c MeshPattern::end_patch(). + * + * @code +Cairo::RefPtr pattern = Cairo::MeshPattern::create(); + +// Add a Coons patch +pattern->begin_patch(); +pattern->move_to(0, 0); +pattern->curve_to(30, -30, 60, 30, 100, 0); +pattern->curve_to(60, 30, 130, 60, 100, 100); +pattern->curve_to(60, 70, 30, 130, 0, 100); +pattern->curve_to(30, 70, -30, 30, 0, 0); +pattern->set_corner_color_rgb(0, 1, 0, 0); +pattern->set_corner_color_rgb(1, 0, 1, 0); +pattern->set_corner_color_rgb(2, 0, 0, 1); +pattern->set_corner_color_rgb(3, 1, 1, 0); +pattern->end_patch(); + +// Add a Gouraud-shaded triangle +pattern->begin_patch() +pattern->move_to(100, 100); +pattern->line_to(130, 130); +pattern->line_to(130, 70); +pattern->set_corner_color_rgb(0, 1, 0, 0); +pattern->set_corner_color_rgb(1, 0, 1, 0); +pattern->set_corner_color_rgb(2, 0, 0, 1); +pattern->end_patch() + + @endcode + + * When two patches overlap, the last one that has been added is drawn over the + * first one. + * + * When a patch folds over itself, points are sorted depending on their + * parameter coordinates inside the patch. The v coordinate ranges from 0 to 1 + * when moving from side 3 to side 1; the u coordinate ranges from 0 to 1 when + * going from side 0 to side 2. Points with higher v coordinate hide points + * with lower v coordinate. When two points have the same v coordinate, the one + * with higher u coordinate is above. This means that points nearer to side 1 + * are above points nearer to side 3; when this is not sufficient to decide + * which point is above (for example when both points belong to side 1 or side + * 3) points nearer to side 2 are above points nearer to side 0. + * + * For a complete definition of tensor-product patches, see the PDF + * specification (ISO32000), which describes the parametrization in detail. + * + * @note The coordinates are always in pattern space. For a new pattern, + * pattern space is identical to user space, but the relationship between the + * spaces can be changed with @c Pattern::set_matrix(). + * + * @since 1.12 + */ +class MeshPattern : public Pattern { +public: + + /** + * Create a C++ wrapper for the C instance. This C++ instance should then be + * given to a RefPtr. + * + * @param cobject The C instance. + * @param has_reference whether we already have a reference. Otherwise, the + * constructor will take an extra reference. + * + * @since 1.12 + */ + explicit MeshPattern(cairo_pattern_t* cobject, bool has_reference = false); + virtual ~MeshPattern(); + + /** + * Begin a patch in a mesh pattern. + * + * After calling this function, the patch shape should be defined with + * @c MeshPattern::move_to(), @c MeshPattern::line_to() and + * @c MeshPattern::curve_to(). + * + * After defining the patch, cairo_mesh_pattern_end_patch() must be called + * before using pattern as a source or mask. + * + * @throws Cairo::logic_error if the pattern already has a current patch. + * + * @since 1.12 + */ + void begin_patch(); + + /** + * Indicates the end of the current patch in a mesh pattern. + * + * If the current patch has less than 4 sides, it is closed with a straight + * line from the current point to the first point of the patch as if + * @c MeshPattern::line_to() was used. + * + * @throws Cairo::logic_error if the pattern has no current patch or the + * current patch has no current point. + * + * @since 1.12 + */ + void end_patch(); + + /** + * Define the first point of the current patch in a mesh pattern. + * + * After this call the current point will be (x, y). + * + * @param x, y the X and Y coordinates of the new position + * + * @throws Cairo::logic_error if the pattern has no current patch or the + * current patch already has at least one side. + * + * @since 1.12 + */ + void move_to(double x, double y); + + /** + * Adds a line to the current patch from the current point to position (x, y) + * in pattern-space coordinates. + * + * If there is no current point before the call to @c MeshPattern::line_to() + * this function will behave as @c MeshPattern::move_to(x, y). + * + * After this call the current point will be (x, y). + * + * @param x, y the X and Y coordinates of the end of the new line + * + * @throws Cairo::logic_error if the pattern has no current patch or the + * current patch already has 4 sides. + * + * @since 1.12 + */ + void line_to(double x, double y); + + /** + * Adds a cubic Bézier spline to the current patch from the current point to + * position (x3, y3) in pattern-space coordinates, using (x1, y1) and (x2, + * y2) as the control points. + * + * If the current patch has no current point before the call to + * @c MeshPattern::curve_to(), this function will behave as if preceded by + * a call to @c MeshPattern::move_to(x1, y1). + * + * After this call the current point will be (x3, y3). + * + * @param x1, y1 the X and Y coordinates of the first control point + * @param x2, y2 the X and Y coordinates of the second control point + * @param x3, y3 the X and Y coordinates of the end of the curve + * + * @throws Cairo::logic_error if pattern has no current patch or the current + * patch already has 4 sides. + * + * @since 1.12 + */ + void curve_to(double x1, double y1, double x2, double y2, + double x3, double y3); + + /** + * Sets an internal control point of the current patch. + * + * Valid values for point_num are from 0 to 3 and identify the control points. + * + * @param point_num the control point to set the position for + * @param x, y the X and Y corrdinates of the control point + * + * @throws Cairo::logic_error if @a point_num is not valid or the pattern has + * no current patch. + * + * @since 1.12 + */ + void set_control_point(unsigned point_num, double x, double y); + + /** + * Sets the color of a corner of the current patch in a mesh pattern. + * + * The color is specified in the same way as in @c set_source_rgb(). + * + * Valid values for @a corner_num are from 0 to 3 and identify the corners. + * + * @param corner_num the corner to set the color for + * @param red, green, blue the red, green and blue components of the color + * respectively. + * @throws Cairo::logic_error if @a point_num is not valid or the pattern has + * no current patch. + * + * @since 1.12 + */ + void set_corner_color_rgb(unsigned int corner_num, double red, double green, + double blue); + + /** + * Sets the color of a corner of the current patch in a mesh pattern. + * + * The color is specified in the same way as in @c set_source_rgba(). + * + * Valid values for @a corner_num are from 0 to 3 and identify the corners. + * + * @param corner_num the corner to set the color for + * @param red, green, blue, alpha the red, green, blue and alpha components + * of the color respectively. + * @throws Cairo::logic_error if @a point_num is not valid or the pattern has + * no current patch. + * + * @since 1.12 + */ + void set_corner_color_rgba(unsigned int corner_num, double red, double green, + double blue, double alpha); + + /** + * Returns the number of patches specified in the given mesh pattern. + * + * The number only includes patches which have been finished by calling + * @c MeshPattern::end_patch(). For example it will be 0 during the + * definition of the first patch. + * + * @since 1.12 + */ + unsigned get_patch_count() const; + +#if __cplusplus >= 201103L + /** + * Retruns path defining the patch @a patch_num for the mesh pattern. + * + * @a patch_num can range 0 to 1 less than the number returned by @c + * get_patch_count(). + * + * @param patch_num the patch number to return data for + * + * @throws Cairo::logic_error if @a patch_num or @a point_num is not valid + * for the pattern + * + * @since 1.12 + */ + Path get_path(unsigned patch_num) const; +#endif + + /** + * Gets the control point @a point_num of patch @a patch_num for a mesh + * pattern. + * + * @a patch_num can range 0 to 1 less than the number returned by + * @c get_patch_count(). + * + * Valid values for @a point_num are from 0 to 3 and identify the control + * points. + * + * @param patch_num the patch number to return data for + * @param point_num the control point number to return data for + * @param x, y return value for the X and Y corrdinates of the control point. + * + * @throws Cairo::logic_error if @a patch_num or @a point_num is not valid + * for the pattern + * + * @since 1.12 + */ + void get_control_point(unsigned patch_num, unsigned point_num, + double& x, double& y); + + /** + * Gets the color information in corner @a corner_num of patch @a patch_num + * for a mesh pattern. + * + * @a patch_num can range 0 to 1 less than the number returned by + * @c get_patch_count(). + * + * Valid values for @a point_num are from 0 to 3 and identify the control + * points. + * + * @param patch_num the patch number to return data for + * @param corner_num the corner number to return data for + * @param red, green, blue, alpha return value for the red, green, blue and + * alpha components of the corner color respectively. + * + * @throws Cairo::logic_error if @a patch_num or @a point_num is not valid + * for the pattern + * + * @since 1.12 + */ + void get_corner_color_rgba(unsigned patch_num, unsigned corner_num, + double& red, double& green, double& blue, + double& alpha); + + /** + * Creates a new mesh pattern. + * + * Throws an exception on error. + * + * @since 1.12 + */ + static RefPtr create(); + +}; + +} // namespace Cairo + +#endif //__CAIROMM_MESH_PATTERN_H + diff --git a/cairomm/path.cc b/cairomm/path.cc index 8040aa3..855bed9 100644 --- a/cairomm/path.cc +++ b/cairomm/path.cc @@ -19,18 +19,11 @@ #include #include #include +#include namespace Cairo { -/* -Path::Path() -: m_cobject(0) -{ - m_cobject = cairo_path_create(); -} -*/ - Path::Path(cairo_path_t* cobject, bool take_ownership) : m_cobject(0) { diff --git a/cairomm/path.h b/cairomm/path.h index 28d843f..56f65e1 100644 --- a/cairomm/path.h +++ b/cairomm/path.h @@ -38,10 +38,28 @@ namespace Cairo class Path { public: - //Path(); +#if __cplusplus >= 201103L + Path() : + m_cobject(0) + { + } +#endif + explicit Path(cairo_path_t* cobject, bool take_ownership = false); //Path(const Path& src); +#if __cplusplus >= 201103L + Path(Path&& other) : + m_cobject(other.m_cobject) + { + } + + Path& operator=(Path&& other) + { + std::swap(m_cobject, other.m_cobject); + } +#endif + virtual ~Path(); //Path& operator=(const Path& src); -- 1.9.rc1