/* Copyright (C) 2005 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. */ /* M_PI is defined in math.h in the case of Microsoft Visual C++ */ #if defined(_MSC_VER) #define _USE_MATH_DEFINES #endif #include #include #include #include #include #include #include /* M_PI is defined in math.h in the case of Microsoft Visual C++ */ #if defined(_MSC_VER) #define _USE_MATH_DEFINES #endif /* Solaris et. al. need math.h for M_PI too */ #include using namespace Cairo::Private; namespace Cairo { Context::Context(const RefPtr& target) : m_cobject(nullptr) { m_cobject = cairo_create(target->cobj()); check_object_status_and_throw_exception(*this); } RefPtr Context::create(const RefPtr& target) { return RefPtr(new Context(target)); } Context::Context(cairo_t* cobject, bool has_reference) : m_cobject(nullptr) { if(has_reference) m_cobject = cobject; else m_cobject = cairo_reference(cobject); } Context::~Context() { if(m_cobject) cairo_destroy(m_cobject); } void Context::reference() const { cairo_reference(const_cast(cobj())); } void Context::unreference() const { cairo_destroy(const_cast(cobj())); } void Context::save() { cairo_save(cobj()); check_object_status_and_throw_exception(*this); } void Context::restore() { cairo_restore(cobj()); check_object_status_and_throw_exception(*this); } void Context::set_operator(Operator op) { cairo_set_operator(cobj(), static_cast(op)); check_object_status_and_throw_exception(*this); } void Context::set_source(const RefPtr& source) { cairo_set_source(cobj(), const_cast(source->cobj())); check_object_status_and_throw_exception(*this); } void Context::set_source_rgb(double red, double green, double blue) { cairo_set_source_rgb(cobj(), red, green, blue); check_object_status_and_throw_exception(*this); } void Context::set_source_rgba(double red, double green, double blue, double alpha) { cairo_set_source_rgba(cobj(), red, green, blue, alpha); check_object_status_and_throw_exception(*this); } void Context::set_source(const RefPtr& surface, double x, double y) { cairo_set_source_surface(cobj(), surface->cobj(), x, y); check_object_status_and_throw_exception(*this); } void Context::set_tolerance(double tolerance) { cairo_set_tolerance(cobj(), tolerance); check_object_status_and_throw_exception(*this); } void Context::set_antialias(Antialias antialias) { cairo_set_antialias(cobj(), static_cast(antialias)); check_object_status_and_throw_exception(*this); } void Context::set_fill_rule(FillRule fill_rule) { cairo_set_fill_rule(cobj(), static_cast(fill_rule)); check_object_status_and_throw_exception(*this); } void Context::set_line_width(double width) { cairo_set_line_width(cobj(), width); check_object_status_and_throw_exception(*this); } void Context::set_line_cap(LineCap line_cap) { cairo_set_line_cap(cobj(), static_cast(line_cap)); check_object_status_and_throw_exception(*this); } void Context::set_line_join(LineJoin line_join) { cairo_set_line_join(cobj(), static_cast(line_join)); check_object_status_and_throw_exception(*this); } void Context::set_dash(std::valarray& dashes, double offset) { std::vector v(dashes.size()); for(size_t i = 0; i < dashes.size(); ++i) v[i] = dashes[i]; set_dash(v, offset); } void Context::set_dash(std::vector& dashes, double offset) { cairo_set_dash(cobj(), (dashes.empty() ? 0 : &dashes[0]), dashes.size(), offset); check_object_status_and_throw_exception(*this); } void Context::set_dash(const std::valarray& dashes, double offset) { std::vector v(dashes.size()); for(size_t i = 0; i < dashes.size(); ++i) v[i] = dashes[i]; set_dash(v, offset); } void Context::set_dash(const std::vector& dashes, double offset) { cairo_set_dash(cobj(), (dashes.empty() ? 0 : &dashes[0]), dashes.size(), offset); check_object_status_and_throw_exception(*this); } void Context::unset_dash() { cairo_set_dash(cobj(), NULL, 0, 0.0); check_object_status_and_throw_exception(*this); } void Context::set_miter_limit(double limit) { cairo_set_miter_limit(cobj(), limit); check_object_status_and_throw_exception(*this); } void Context::translate(double tx, double ty) { cairo_translate(cobj(), tx, ty); check_object_status_and_throw_exception(*this); } void Context::scale(double sx, double sy) { cairo_scale(cobj(), sx, sy); check_object_status_and_throw_exception(*this); } void Context::rotate(double angle_radians) { cairo_rotate(cobj(), angle_radians); check_object_status_and_throw_exception(*this); } void Context::rotate_degrees(double angle_degrees) { cairo_rotate(cobj(), angle_degrees * M_PI/180.0); check_object_status_and_throw_exception(*this); } void Context::transform(const Matrix& matrix) { cairo_transform(cobj(), &matrix); check_object_status_and_throw_exception(*this); } void Context::transform(const cairo_matrix_t& matrix) { cairo_transform(cobj(), &matrix); check_object_status_and_throw_exception(*this); } void Context::set_matrix(const Matrix& matrix) { cairo_set_matrix(cobj(), &matrix); check_object_status_and_throw_exception(*this); } void Context::set_matrix(const cairo_matrix_t& matrix) { cairo_set_matrix(cobj(), &matrix); check_object_status_and_throw_exception(*this); } void Context::set_identity_matrix() { cairo_identity_matrix(cobj()); check_object_status_and_throw_exception(*this); } //deprecated: void Context::user_to_device(double& x, double& y) { const Context* constThis = this; constThis->user_to_device(x, y); } void Context::user_to_device(double& x, double& y) const { cairo_user_to_device(const_cast(cobj()), &x, &y); check_object_status_and_throw_exception(*this); } //deprecated: void Context::user_to_device_distance(double& dx, double& dy) { const Context* constThis = this; constThis->user_to_device_distance(dx, dy); } void Context::user_to_device_distance(double& dx, double& dy) const { cairo_user_to_device_distance(const_cast(cobj()), &dx, &dy); check_object_status_and_throw_exception(*this); } //deprecated: void Context::device_to_user(double& x, double& y) { const Context* constThis = this; constThis->device_to_user(x, y); } void Context::device_to_user(double& x, double& y) const { cairo_device_to_user(const_cast(cobj()), &x, &y); check_object_status_and_throw_exception(*this); } //deprecated: void Context::device_to_user_distance(double& dx, double& dy) { const Context* constThis = this; constThis->device_to_user_distance(dx, dy); } void Context::device_to_user_distance(double& dx, double& dy) const { cairo_device_to_user_distance(const_cast(cobj()), &dx, &dy); check_object_status_and_throw_exception(*this); } void Context::begin_new_path() { cairo_new_path(cobj()); check_object_status_and_throw_exception(*this); } void Context::begin_new_sub_path() { cairo_new_sub_path(cobj()); check_object_status_and_throw_exception(*this); } void Context::move_to(double x, double y) { cairo_move_to(cobj(), x, y); check_object_status_and_throw_exception(*this); } void Context::line_to(double x, double y) { cairo_line_to(cobj(), x, y); check_object_status_and_throw_exception(*this); } void Context::curve_to(double x1, double y1, double x2, double y2, double x3, double y3) { cairo_curve_to(cobj(), x1, y1, x2, y2, x3, y3); check_object_status_and_throw_exception(*this); } void Context::arc(double xc, double yc, double radius, double angle1, double angle2) { cairo_arc(cobj(), xc, yc, radius, angle1, angle2); check_object_status_and_throw_exception(*this); } void Context::arc_negative(double xc, double yc, double radius, double angle1, double angle2) { cairo_arc_negative(cobj(), xc, yc, radius, angle1, angle2); check_object_status_and_throw_exception(*this); } void Context::rel_move_to(double dx, double dy) { cairo_rel_move_to(cobj(), dx, dy); check_object_status_and_throw_exception(*this); } void Context::rel_line_to(double dx, double dy) { cairo_rel_line_to(cobj(), dx, dy); check_object_status_and_throw_exception(*this); } void Context::rel_curve_to(double dx1, double dy1, double dx2, double dy2, double dx3, double dy3) { cairo_rel_curve_to(cobj(), dx1, dy1, dx2, dy2, dx3, dy3); check_object_status_and_throw_exception(*this); } void Context::rectangle(double x, double y, double width, double height) { cairo_rectangle(cobj(), x, y, width, height); check_object_status_and_throw_exception(*this); } void Context::close_path() { cairo_close_path(cobj()); check_object_status_and_throw_exception(*this); } void Context::paint() { cairo_paint(cobj()); check_object_status_and_throw_exception(*this); } void Context::paint_with_alpha(double alpha) { cairo_paint_with_alpha(cobj(), alpha); check_object_status_and_throw_exception(*this); } void Context::mask(const RefPtr& pattern) { cairo_mask(cobj(), const_cast(pattern->cobj())); check_object_status_and_throw_exception(*this); } void Context::mask(const RefPtr& surface, double surface_x, double surface_y) { cairo_mask_surface(cobj(), const_cast(surface->cobj()), surface_x, surface_y); check_object_status_and_throw_exception(*this); } void Context::stroke() { cairo_stroke(cobj()); check_object_status_and_throw_exception(*this); } void Context::stroke_preserve() { cairo_stroke_preserve(cobj()); check_object_status_and_throw_exception(*this); } void Context::fill() { cairo_fill(cobj()); check_object_status_and_throw_exception(*this); } void Context::fill_preserve() { cairo_fill_preserve(cobj()); check_object_status_and_throw_exception(*this); } void Context::copy_page() { cairo_copy_page(cobj()); check_object_status_and_throw_exception(*this); } void Context::show_page() { cairo_show_page(cobj()); check_object_status_and_throw_exception(*this); } bool Context::in_stroke(double x, double y) const { const bool result = cairo_in_stroke(const_cast(cobj()), x, y); check_object_status_and_throw_exception(*this); return result; } bool Context::in_fill(double x, double y) const { const bool result = cairo_in_fill(const_cast(cobj()), x, y); check_object_status_and_throw_exception(*this); return result; } bool Context::in_clip(double x, double y) const { const bool result = cairo_in_clip(const_cast(cobj()), x, y); check_object_status_and_throw_exception(*this); return result; } void Context::get_stroke_extents(double& x1, double& y1, double& x2, double& y2) const { cairo_stroke_extents(const_cast(cobj()), &x1, &y1, &x2, &y2); check_object_status_and_throw_exception(*this); } void Context::get_fill_extents(double& x1, double& y1, double& x2, double& y2) const { cairo_fill_extents(const_cast(cobj()), &x1, &y1, &x2, &y2); check_object_status_and_throw_exception(*this); } void Context::reset_clip() { cairo_reset_clip(cobj()); check_object_status_and_throw_exception(*this); } void Context::clip() { cairo_clip(cobj()); check_object_status_and_throw_exception(*this); } void Context::clip_preserve() { cairo_clip_preserve(cobj()); check_object_status_and_throw_exception(*this); } void Context::get_clip_extents(double& x1, double& y1, double& x2, double& y2) const { cairo_clip_extents(const_cast(const_cast(cobj())), &x1, &y1, &x2, &y2); check_object_status_and_throw_exception(*this); } void Context::copy_clip_rectangle_list(std::vector& rectangles) const { cairo_rectangle_list_t* c_list = nullptr; // It would be nice if the cairo interface didn't copy it into a C array first // and just let us do the copying... c_list = cairo_copy_clip_rectangle_list(const_cast(const_cast(cobj()))); // the rectangle list contains a status field that we need to check and the // cairo context also has a status that we need to check // FIXME: do we want to throw an exception if the clip can't be represented by // rectangles? or do we just want to return an empty list? check_status_and_throw_exception(c_list->status); check_object_status_and_throw_exception(*this); // copy the C array into the passed C++ list rectangles.assign(c_list->rectangles, c_list->rectangles + c_list->num_rectangles); // free the memory allocated to the C array since we've copied it into a // standard C++ container cairo_rectangle_list_destroy(c_list); } void Context::select_font_face(const std::string& family, FontSlant slant, FontWeight weight) { cairo_select_font_face(cobj(), family.c_str(), static_cast(slant), static_cast(weight)); check_object_status_and_throw_exception(*this); } void Context::set_font_size(double size) { cairo_set_font_size(cobj(), size); check_object_status_and_throw_exception(*this); } void Context::set_font_matrix(const Matrix& matrix) { cairo_set_font_matrix(cobj(), &matrix); check_object_status_and_throw_exception(*this); } void Context::set_font_matrix(const cairo_matrix_t& matrix) { cairo_set_font_matrix(cobj(), &matrix); check_object_status_and_throw_exception(*this); } void Context::get_font_matrix(Matrix& matrix) const { cairo_get_font_matrix(const_cast(cobj()), &matrix); check_object_status_and_throw_exception(*this); } void Context::get_font_matrix(cairo_matrix_t& matrix) const { cairo_get_font_matrix(const_cast(cobj()), &matrix); check_object_status_and_throw_exception(*this); } void Context::set_font_options(const FontOptions& options) { cairo_set_font_options(cobj(), options.cobj()); check_object_status_and_throw_exception(*this); } void Context::get_font_options(FontOptions& options) const { cairo_get_font_options(const_cast(cobj()), options.cobj()); check_object_status_and_throw_exception(*this); } void Context::set_scaled_font(const RefPtr& scaled_font) { cairo_set_scaled_font(cobj(), scaled_font->cobj()); check_object_status_and_throw_exception(*this); } RefPtr Context::get_scaled_font() { auto font = cairo_get_scaled_font(cobj()); check_object_status_and_throw_exception(*this); return RefPtr(new ScaledFont(font, false /* does not have reference */)); } void Context::show_text(const std::string& utf8) { cairo_show_text(cobj(), utf8.c_str()); check_object_status_and_throw_exception(*this); } void Context::show_text_glyphs(const std::string& utf8, const std::vector& glyphs, const std::vector& clusters, TextClusterFlags cluster_flags) { cairo_show_text_glyphs(cobj(), utf8.c_str(), utf8.size(), (glyphs.empty() ? 0 : &glyphs[0]), glyphs.size(), (clusters.empty() ? 0 : &clusters[0]), clusters.size(), static_cast(cluster_flags)); check_object_status_and_throw_exception(*this); } void Context::show_glyphs(const std::vector& glyphs) { cairo_show_glyphs(cobj(), const_cast((glyphs.empty() ? 0 : &glyphs[0])), glyphs.size()); check_object_status_and_throw_exception(*this); } RefPtr Context::get_font_face() { auto cfontface = cairo_get_font_face(cobj()); check_object_status_and_throw_exception(*this); return RefPtr(new FontFace(cfontface, false /* does not have reference */)); } RefPtr Context::get_font_face() const { auto cfontface = cairo_get_font_face(const_cast(cobj())); check_object_status_and_throw_exception(*this); return RefPtr(new FontFace(cfontface, false /* does not have reference */)); } void Context::get_font_extents(FontExtents& extents) const { cairo_font_extents(const_cast(cobj()), &extents); check_object_status_and_throw_exception(*this); } void Context::set_font_face(const RefPtr& font_face) { cairo_set_font_face(cobj(), const_cast(font_face->cobj())); check_object_status_and_throw_exception(*this); } void Context::get_text_extents(const std::string& utf8, TextExtents& extents) const { cairo_text_extents(const_cast(cobj()), utf8.c_str(), &extents); check_object_status_and_throw_exception(*this); } void Context::get_glyph_extents(const std::vector& glyphs, TextExtents& extents) const { cairo_glyph_extents(const_cast(cobj()), const_cast(glyphs.empty() ? 0 : &glyphs[0]), glyphs.size(), &extents); check_object_status_and_throw_exception(*this); } void Context::text_path(const std::string& utf8) { cairo_text_path(cobj(), utf8.c_str()); check_object_status_and_throw_exception(*this); } void Context::glyph_path(const std::vector& glyphs) { cairo_glyph_path(cobj(), const_cast(glyphs.empty() ? 0 : &glyphs[0]), glyphs.size()); check_object_status_and_throw_exception(*this); } Operator Context::get_operator() const { const auto result = static_cast(cairo_get_operator(const_cast(cobj()))); check_object_status_and_throw_exception(*this); return result; } static RefPtr get_pattern_wrapper (cairo_pattern_t* pattern) { auto pattern_type = cairo_pattern_get_type (pattern); switch (pattern_type) { case CAIRO_PATTERN_TYPE_SOLID: return RefPtr(new SolidPattern(pattern, false /* does not have reference */)); break; case CAIRO_PATTERN_TYPE_SURFACE: return RefPtr(new SurfacePattern(pattern, false /* does not have reference */)); break; case CAIRO_PATTERN_TYPE_LINEAR: return RefPtr(new LinearGradient(pattern, false /* does not have reference */)); break; case CAIRO_PATTERN_TYPE_RADIAL: return RefPtr(new RadialGradient(pattern, false /* does not have reference */)); break; default: return RefPtr(new Pattern(pattern, false /* does not have reference */)); } } RefPtr Context::get_source() { auto pattern = cairo_get_source(cobj()); check_object_status_and_throw_exception(*this); return get_pattern_wrapper (pattern); } RefPtr Context::get_source() const { auto pattern = cairo_get_source(const_cast(cobj())); check_object_status_and_throw_exception(*this); return RefPtr::cast_const (get_pattern_wrapper (pattern)); } double Context::get_tolerance() const { const auto result = cairo_get_tolerance(const_cast(cobj())); check_object_status_and_throw_exception(*this); return result; } Antialias Context::get_antialias() const { const auto result = static_cast(cairo_get_antialias(const_cast(cobj()))); check_object_status_and_throw_exception(*this); return result; } bool Context::has_current_point() const { return cairo_has_current_point(const_cast(cobj())); } void Context::get_current_point(double& x, double& y) const { cairo_get_current_point(const_cast(cobj()), &x, &y); check_object_status_and_throw_exception(*this); } FillRule Context::get_fill_rule() const { const auto result = static_cast(cairo_get_fill_rule(const_cast(cobj()))); check_object_status_and_throw_exception(*this); return result; } double Context::get_line_width() const { const auto result = cairo_get_line_width(const_cast(cobj())); check_object_status_and_throw_exception(*this); return result; } LineCap Context::get_line_cap() const { const auto result = static_cast(cairo_get_line_cap(const_cast(cobj()))); check_object_status_and_throw_exception(*this); return result; } LineJoin Context::get_line_join() const { const auto result = static_cast(cairo_get_line_join(const_cast(cobj()))); check_object_status_and_throw_exception(*this); return result; } double Context::get_miter_limit() const { const auto result = cairo_get_miter_limit(const_cast(cobj())); check_object_status_and_throw_exception(*this); return result; } void Context::get_dash(std::vector& dashes, double& offset) const { // Allocate this array dynamically because some compilers complain about // allocating arrays on the stack when the array size isn't a compile-time // constant... const auto cnt = cairo_get_dash_count(const_cast(cobj())); auto dash_array = new double[cnt]; cairo_get_dash(const_cast(cobj()), dash_array, &offset); check_object_status_and_throw_exception(*this); dashes.assign(dash_array, dash_array + cnt); delete[] dash_array; } void Context::get_matrix(Matrix& matrix) { cairo_get_matrix(cobj(), &matrix); check_object_status_and_throw_exception(*this); } void Context::get_matrix(cairo_matrix_t& matrix) { cairo_get_matrix(cobj(), &matrix); check_object_status_and_throw_exception(*this); } Matrix Context::get_matrix() const { Cairo::Matrix m; cairo_get_matrix(const_cast(cobj()), (cairo_matrix_t*)&m); check_object_status_and_throw_exception(*this); return m; } static RefPtr get_surface_wrapper (cairo_surface_t* surface) { auto surface_type = cairo_surface_get_type (surface); switch (surface_type) { case CAIRO_SURFACE_TYPE_IMAGE: return RefPtr(new ImageSurface(surface, false /* does not have reference */)); break; #if CAIRO_HAS_PDF_SURFACE case CAIRO_SURFACE_TYPE_PDF: return RefPtr(new PdfSurface(surface, false /* does not have reference */)); break; #endif #if CAIRO_HAS_PS_SURFACE case CAIRO_SURFACE_TYPE_PS: return RefPtr(new PsSurface(surface, false /* does not have reference */)); break; #endif #if CAIRO_HAS_XLIB_SURFACE case CAIRO_SURFACE_TYPE_XLIB: return wrap_surface_xlib(surface); break; #endif #if CAIRO_HAS_GLITZ_SURFACE case CAIRO_SURFACE_TYPE_GLITZ: return RefPtr(new GlitzSurface(surface, false /* does not have reference */)); break; #endif #if CAIRO_HAS_QUARTZ_SURFACE case CAIRO_SURFACE_TYPE_QUARTZ: return wrap_surface_quartz(surface); break; #endif #if CAIRO_HAS_SCRIPT_SURFACE case CAIRO_SURFACE_TYPE_SCRIPT: return RefPtr(new ScriptSurface(surface, false)); break; #endif #if CAIRO_HAS_WIN32_SURFACE case CAIRO_SURFACE_TYPE_WIN32: return wrap_surface_win32(surface); break; #endif #if CAIRO_HAS_SVG_SURFACE case CAIRO_SURFACE_TYPE_SVG: return RefPtr(new SvgSurface(surface, false /* does not have reference */)); break; #endif // the following surfaces are not directly supported in cairomm yet case CAIRO_SURFACE_TYPE_DIRECTFB: case CAIRO_SURFACE_TYPE_OS2: case CAIRO_SURFACE_TYPE_BEOS: case CAIRO_SURFACE_TYPE_XCB: default: return RefPtr(new Surface(surface, false /* does not have reference */)); } } RefPtr Context::get_target() { auto surface = cairo_get_target(const_cast(cobj())); check_object_status_and_throw_exception(*this); return get_surface_wrapper (surface); } RefPtr Context::get_target() const { auto surface = cairo_get_target(const_cast(cobj())); check_object_status_and_throw_exception(*this); return RefPtr::cast_const (get_surface_wrapper (surface)); } Path* Context::copy_path() const { auto cresult = cairo_copy_path(const_cast(cobj())); check_object_status_and_throw_exception(*this); return new Path(cresult, true /* take ownership */); //The caller must delete it. } void Context::get_path_extents(double& x1, double& y1, double& x2, double& y2) const { cairo_path_extents(const_cast(cobj()), &x1, &y1, &x2, &y2); check_object_status_and_throw_exception(*this); } Path* Context::copy_path_flat() const { auto cresult = cairo_copy_path_flat(const_cast(cobj())); check_object_status_and_throw_exception(*this); return new Path(cresult, true /* take ownership */); //The caller must delete it. } void Context::append_path(const Path& path) { cairo_append_path(cobj(), const_cast(path.cobj())); check_object_status_and_throw_exception(*this); } void Context::push_group() { cairo_push_group(cobj()); check_object_status_and_throw_exception(*this); } void Context::push_group_with_content(Content content) { cairo_push_group_with_content(cobj(), static_cast(content)); check_object_status_and_throw_exception(*this); } RefPtr Context::pop_group() { auto pattern = cairo_pop_group(cobj()); check_object_status_and_throw_exception(*this); return get_pattern_wrapper(pattern); } void Context::pop_group_to_source() { cairo_pop_group_to_source(cobj()); check_object_status_and_throw_exception(*this); } RefPtr Context::get_group_target() { auto surface = cairo_get_group_target(cobj()); // surface can be NULL if you're not between push/pop group calls if(!surface) { // FIXME: is this really the right way to handle this? throw_exception(CAIRO_STATUS_NULL_POINTER); } return get_surface_wrapper(surface); } RefPtr Context::get_group_target() const { auto surface = cairo_get_group_target(const_cast(cobj())); // surface can be NULL if you're not between push/pop group calls if(!surface) { // FIXME: is this really the right way to handle this? throw_exception(CAIRO_STATUS_NULL_POINTER); } return get_surface_wrapper(surface); } } //namespace Cairo // vim: ts=2 sw=2 et