/* 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. */ #include #include #include namespace Cairo { static cairo_user_data_key_t USER_DATA_KEY_WRITE_FUNC = {0}; static cairo_user_data_key_t USER_DATA_KEY_READ_FUNC = {0}; static void free_slot(void* data) { auto slot = static_cast(data); delete slot; } static Surface::SlotWriteFunc* get_slot(cairo_surface_t* surface) { return static_cast(cairo_surface_get_user_data(surface, &USER_DATA_KEY_WRITE_FUNC)); } static void set_read_slot(cairo_surface_t* surface, Surface::SlotReadFunc* slot) { // the slot will automatically be freed by free_slot() when the underlying C // instance is destroyed cairo_surface_set_user_data(surface, &USER_DATA_KEY_READ_FUNC, slot, &free_slot); } static void set_write_slot(cairo_surface_t* surface, Surface::SlotWriteFunc* slot) { // the slot will automatically be freed by free_slot() when the underlying C // instance is destroyed cairo_surface_set_user_data(surface, &USER_DATA_KEY_WRITE_FUNC, slot, &free_slot); } cairo_status_t read_func_wrapper(void* closure, unsigned char* data, unsigned int length) { if (!closure) return CAIRO_STATUS_READ_ERROR; auto read_func = static_cast(closure); return static_cast((*read_func)(data, length)); } cairo_status_t write_func_wrapper(void* closure, const unsigned char* data, unsigned int length) { if (!closure) return CAIRO_STATUS_WRITE_ERROR; auto write_func = static_cast(closure); return static_cast((*write_func)(data, length)); } Surface::Surface(cairo_surface_t* cobject, bool has_reference) : m_cobject(nullptr) { if(has_reference) m_cobject = cobject; else m_cobject = cairo_surface_reference(cobject); } Surface::~Surface() { if(m_cobject) cairo_surface_destroy(m_cobject); } void Surface::finish() { cairo_surface_finish(cobj()); check_object_status_and_throw_exception(*this); } const unsigned char* Surface::get_mime_data(const std::string& mime_type, unsigned long& length) { const unsigned char* data = nullptr; cairo_surface_get_mime_data(const_cast(cobj()), mime_type.c_str(), &data, &length); check_object_status_and_throw_exception(*this); return data; } static void on_cairo_destroy(void *data) { auto slot = static_cast(data); if(!slot) return; (*slot)(); delete slot; } void Surface::set_mime_data(const std::string& mime_type, unsigned char* data, unsigned long length, const SlotDestroy& slot_destroy) { auto copy = new SlotDestroy(slot_destroy); //Deleted when the callback is called once. cairo_surface_set_mime_data(const_cast(cobj()), mime_type.c_str(), data, length, &on_cairo_destroy, copy); check_object_status_and_throw_exception(*this); } void Surface::unset_mime_data(const std::string& mime_type) { cairo_surface_set_mime_data(const_cast(cobj()), mime_type.c_str(), 0, 0, 0, 0); check_object_status_and_throw_exception(*this); } void Surface::get_font_options(FontOptions& options) const { auto cfontoptions = cairo_font_options_create(); cairo_surface_get_font_options(const_cast(cobj()), cfontoptions); options = FontOptions(cfontoptions); cairo_font_options_destroy(cfontoptions); check_object_status_and_throw_exception(*this); } void Surface::flush() { cairo_surface_flush(cobj()); check_object_status_and_throw_exception(*this); } void Surface::mark_dirty() { cairo_surface_mark_dirty(cobj()); check_object_status_and_throw_exception(*this); } void Surface::mark_dirty(int x, int y, int width, int height) { cairo_surface_mark_dirty_rectangle(cobj(), x, y, width, height); check_object_status_and_throw_exception(*this); } void Surface::set_device_offset(double x_offset, double y_offset) { cairo_surface_set_device_offset(cobj(), x_offset, y_offset); check_object_status_and_throw_exception(*this); } void Surface::get_device_offset(double& x_offset, double& y_offset) const { cairo_surface_get_device_offset(const_cast(cobj()), &x_offset, &y_offset); } void Surface::set_fallback_resolution(double x_pixels_per_inch, double y_pixels_per_inch) { cairo_surface_set_fallback_resolution(cobj(), x_pixels_per_inch, y_pixels_per_inch); check_object_status_and_throw_exception(*this); } void Surface::get_fallback_resolution(double& x_pixels_per_inch, double& y_pixels_per_inch) const { cairo_surface_get_fallback_resolution(const_cast(cobj()), &x_pixels_per_inch, &y_pixels_per_inch); check_object_status_and_throw_exception(*this); } SurfaceType Surface::get_type() const { auto surface_type = cairo_surface_get_type(const_cast(cobj())); check_object_status_and_throw_exception(*this); return static_cast(surface_type); } Content Surface::get_content() const { auto content = cairo_surface_get_content(const_cast(cobj())); check_object_status_and_throw_exception(*this); return static_cast(content); } void Surface::copy_page() { cairo_surface_copy_page(cobj()); check_object_status_and_throw_exception(*this); } void Surface::show_page() { cairo_surface_show_page(cobj()); check_object_status_and_throw_exception(*this); } bool Surface::has_show_text_glyphs() const { bool result = cairo_surface_has_show_text_glyphs(const_cast(cobj())); check_object_status_and_throw_exception(*this); return result; } #ifdef CAIRO_HAS_PNG_FUNCTIONS void Surface::write_to_png(const std::string& filename) { auto status = cairo_surface_write_to_png(cobj(), filename.c_str()); check_status_and_throw_exception(status); } void Surface::write_to_png_stream(const SlotWriteFunc& write_func) { auto old_slot = get_slot(cobj()); if (old_slot) delete old_slot; auto slot_copy = new SlotWriteFunc(write_func); set_write_slot(cobj(), slot_copy); auto status = cairo_surface_write_to_png_stream(cobj(), &write_func_wrapper, slot_copy /*closure*/); check_status_and_throw_exception(status); } void Surface::write_to_png(cairo_write_func_t write_func, void *closure) { auto status = cairo_surface_write_to_png_stream(cobj(), write_func, closure); check_status_and_throw_exception(status); } #endif RefPtr Surface::get_device() { auto *d = cairo_surface_get_device (m_cobject); if (!d) return RefPtr(); auto surface_type = cairo_surface_get_type(m_cobject); switch (surface_type) { #if CAIRO_HAS_SCRIPT_SURFACE case CAIRO_SURFACE_TYPE_SCRIPT: return RefPtr