From b53bd1cf536a3042adb884150a577b196845fd72 Mon Sep 17 00:00:00 2001 From: Jonathon Jongsma Date: Tue, 19 Aug 2008 12:28:02 -0500 Subject: Add sigc::slot versions of all of the functions that take a cairo_write_func_t or cairo_read_func_t --- .gitignore | 1 + ChangeLog | 7 ++++ cairomm/surface.cc | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++ cairomm/surface.h | 60 ++++++++++++++++++++++++----- tests/Makefile.am | 3 +- tests/test-surface.cc | 89 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 254 insertions(+), 10 deletions(-) create mode 100644 tests/test-surface.cc diff --git a/.gitignore b/.gitignore index d52c623..05d835b 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ examples/text/text_rotate examples/text/toy-text tests/test-context tests/test-font-face +tests/test-surface cairomm/cairommconfig.h* cairomm/stamp-* m4/libtool.m4 diff --git a/ChangeLog b/ChangeLog index 623fb9a..d42b221 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2008-08-19 Jonathon Jongsma + + * cairomm/surface.cc: + * cairomm/surface.h: add sigc::slot versions of all of the functions that take + a cairo_write_func_t or cairo_read_func_t + * tests/Makefile.am: add a couple basic tests for the surfaced slot functions + 2008-08-18 Jonathon Jongsma * cairomm/fontface.h: Add a bunch of documentation for the new FontFace API diff --git a/cairomm/surface.cc b/cairomm/surface.cc index f7393ac..57898c3 100644 --- a/cairomm/surface.cc +++ b/cairomm/surface.cc @@ -22,6 +22,52 @@ 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) +{ + Surface::SlotWriteFunc* 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; + Surface::SlotReadFunc* 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; + Surface::SlotWriteFunc* write_func = static_cast(closure); + return static_cast((*write_func)(data, length)); +} + Surface::Surface(cairo_surface_t* cobject, bool has_reference) : m_cobject(0) { @@ -113,6 +159,19 @@ void Surface::write_to_png(const std::string& filename) check_status_and_throw_exception(status); } +void Surface::write_to_png_stream(const SlotWriteFunc& write_func) +{ + SlotWriteFunc* old_slot = get_slot(m_cobject); + if (old_slot) + delete old_slot; + SlotWriteFunc* slot_copy = new SlotWriteFunc(write_func); + set_write_slot(m_cobject, slot_copy); + ErrorStatus status = cairo_surface_write_to_png_stream(m_cobject, + &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) { ErrorStatus status = cairo_surface_write_to_png_stream(m_cobject, write_func, closure); @@ -171,6 +230,16 @@ RefPtr ImageSurface::create_from_png(std::string filename) return RefPtr(new ImageSurface(cobject, true /* has reference */)); } +RefPtr ImageSurface::create_from_png_stream(const SlotReadFunc& read_func) +{ + SlotReadFunc* slot_copy = new SlotReadFunc(read_func); + cairo_surface_t* cobject = + cairo_image_surface_create_from_png_stream(&read_func_wrapper, slot_copy); + check_status_and_throw_exception(cairo_surface_status(cobject)); + set_read_slot(cobject, slot_copy); + return RefPtr(new ImageSurface(cobject, true /* has reference */)); +} + RefPtr ImageSurface::create_from_png(cairo_read_func_t read_func, void *closure) { cairo_surface_t* cobject = cairo_image_surface_create_from_png_stream(read_func, closure); @@ -249,6 +318,18 @@ RefPtr PdfSurface::create(cairo_write_func_t write_func, void *closu return RefPtr(new PdfSurface(cobject, true /* has reference */)); } +RefPtr PdfSurface::create(const SlotWriteFunc& write_func, double + width_in_points, double height_in_points) +{ + SlotWriteFunc* slot_copy = new SlotWriteFunc(write_func); + cairo_surface_t* cobject = + cairo_pdf_surface_create_for_stream(write_func_wrapper, slot_copy, + width_in_points, height_in_points); + check_status_and_throw_exception(cairo_surface_status(cobject)); + set_write_slot(cobject, slot_copy); + return RefPtr(new PdfSurface(cobject, true /* has reference */)); +} + void PdfSurface::set_size(double width_in_points, double height_in_points) { cairo_pdf_surface_set_size(m_cobject, width_in_points, height_in_points); @@ -278,6 +359,18 @@ RefPtr PsSurface::create(std::string filename, double width_in_points return RefPtr(new PsSurface(cobject, true /* has reference */)); } +RefPtr PsSurface::create(const SlotWriteFunc& write_func, double + width_in_points, double height_in_points) +{ + SlotWriteFunc* slot_copy = new SlotWriteFunc(write_func); + cairo_surface_t* cobject = + cairo_ps_surface_create_for_stream(write_func_wrapper, slot_copy, + width_in_points, height_in_points); + check_status_and_throw_exception(cairo_surface_status(cobject)); + set_write_slot(cobject, slot_copy); + return RefPtr(new PsSurface(cobject, true /* has reference */)); +} + RefPtr PsSurface::create(cairo_write_func_t write_func, void *closure, double width_in_points, double height_in_points) { cairo_surface_t* cobject = cairo_ps_surface_create_for_stream(write_func, closure, width_in_points, height_in_points); @@ -367,6 +460,17 @@ RefPtr SvgSurface::create(std::string filename, double width_in_poin return RefPtr(new SvgSurface(cobject, true /* has reference */)); } +RefPtr SvgSurface::create(const SlotWriteFunc& write_func, double width_in_points, double height_in_points) +{ + SlotWriteFunc* slot_copy = new SlotWriteFunc(write_func); + cairo_surface_t* cobject = + cairo_svg_surface_create_for_stream(write_func_wrapper, slot_copy, + width_in_points, height_in_points); + check_status_and_throw_exception(cairo_surface_status(cobject)); + set_write_slot(cobject, slot_copy); + return RefPtr(new SvgSurface(cobject, true /* has reference */)); +} + RefPtr SvgSurface::create(cairo_write_func_t write_func, void *closure, double width_in_points, double height_in_points) { cairo_surface_t* cobject = cairo_svg_surface_create_for_stream(write_func, closure, width_in_points, height_in_points); diff --git a/cairomm/surface.h b/cairomm/surface.h index 7043fc0..8ec0b5b 100644 --- a/cairomm/surface.h +++ b/cairomm/surface.h @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -59,6 +60,34 @@ namespace Cairo class Surface { public: + /** For example: + * + * ErrorStatus my_write_func(unsigned char* data, unsigned int length); + * + * + * This is the type of function which is called when a backend needs to write + * data to an output stream. It is passed the data to write and the length of + * the data in bytes. The write function should return CAIRO_STATUS_SUCCESS if + * all the data was successfully written, CAIRO_STATUS_WRITE_ERROR otherwise. + * + * @param data the buffer containing the data to write + * @param length the amount of data to write + * @return the status code of the write operation + */ + typedef sigc::slot SlotWriteFunc; + /** + * This is the type of function which is called when a backend needs to read + * data from an input stream. It is passed the buffer to read the data into + * and the length of the data in bytes. The read function should return + * CAIRO_STATUS_SUCCESS if all the data was successfully read, + * CAIRO_STATUS_READ_ERROR otherwise. + * + * @param data the buffer into which to read the data + * @param length the amount of data to read + * @return the status code of the read operation + */ + typedef sigc::slot SlotReadFunc; + /** Create a C++ wrapper for the C instance. This C++ instance should then be * given to a RefPtr. * @@ -187,9 +216,12 @@ public: * * @param write_func The function to be called when the backend needs to * write data to an output stream - * @param closure closure data for the write function + * + * @since 1.8 */ - void write_to_png(cairo_write_func_t write_func, void *closure); //TODO: Use a sigc::slot? + void write_to_png_stream(const SlotWriteFunc& write_func); + /** @deprecated Use write_to_png_stream instead */ + void write_to_png(cairo_write_func_t write_func, void *closure); #endif // CAIRO_HAS_PNG_FUNCTIONS @@ -376,16 +408,17 @@ public: static RefPtr create_from_png(std::string filename); /** Creates a new image surface from PNG data read incrementally via the - * read_func function. + * read_func function. * * @note For this function to be available, cairo must have been compiled * with PNG support. * - * @param read_func function called to read the data of the file - * @param closure data to pass to read_func. - * @return a RefPtr to the new cairo_surface_t initialized with the + * @param read_func function called to read the data of the file + * @return a RefPtr to the new cairo_surface_t initialized with the * contents of the PNG image file. */ + static RefPtr create_from_png_stream(const SlotReadFunc& read_func); + /** @deprecated Use create_from_png_stream instead */ static RefPtr create_from_png(cairo_read_func_t read_func, void *closure); #endif // CAIRO_HAS_PNG_FUNCTIONS @@ -430,10 +463,13 @@ public: * * @param write_func The function to be called when the backend needs to * write data to an output stream - * @param closure closure data for the write function * @param width_in_points The width of the PDF document in points * @param height_in_points The height of the PDF document in points + * + * @since 1.8 */ + static RefPtr create(const SlotWriteFunc& write_func, double width_in_points, double height_in_points); + /** @deprecated */ static RefPtr create(cairo_write_func_t write_func, void *closure, double width_in_points, double height_in_points); /** @@ -500,10 +536,13 @@ public: * * @param write_func The function to be called when the backend needs to * write data to an output stream - * @param closure closure data for the write function * @param width_in_points The width of the PostScript document in points * @param height_in_points The height of the PostScript document in points + * + * @since 1.8 */ + static RefPtr create(const SlotWriteFunc& write_func, double width_in_points, double height_in_points); + /** @deprecated */ static RefPtr create(cairo_write_func_t write_func, void *closure, double width_in_points, double height_in_points); /** @@ -643,10 +682,13 @@ public: * * @param write_func The function to be called when the backend needs to * write data to an output stream - * @param closure closure data for the write function * @param width_in_points The width of the SVG document in points * @param height_in_points The height of the SVG document in points + * + * @since 1.8 */ + static RefPtr create(const SlotWriteFunc& write_func, double width_in_points, double height_in_points); + /** @deprecated */ static RefPtr create(cairo_write_func_t write_func, void *closure, double width_in_points, double height_in_points); /** diff --git a/tests/Makefile.am b/tests/Makefile.am index 03e58a0..9b534a5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,10 +1,11 @@ if AUTOTESTS # build automated 'tests' -TESTS=test-context test-font-face +TESTS=test-context test-font-face test-surface noinst_PROGRAMS = $(TESTS) test_context_SOURCES=test-context.cc test_font_face_SOURCES=test-font-face.cc +test_surface_SOURCES=test-surface.cc else diff --git a/tests/test-surface.cc b/tests/test-surface.cc new file mode 100644 index 0000000..3b3e7d0 --- /dev/null +++ b/tests/test-surface.cc @@ -0,0 +1,89 @@ +#include +#include +#include +using namespace boost::unit_test; +#include +using namespace Cairo; + +static unsigned int test_slot_called = 0; +ErrorStatus test_slot(const unsigned char* /*data*/, unsigned int /*len*/) +{ + test_slot_called++; + return CAIRO_STATUS_SUCCESS; +} + +void test_write_to_png_stream() +{ + RefPtr surface = ImageSurface::create(FORMAT_ARGB32, 1, 1); + surface->write_to_png_stream(sigc::ptr_fun(test_slot)); + BOOST_CHECK(test_slot_called > 0); +} + +void test_pdf_constructor_slot() +{ + test_slot_called = 0; + RefPtr pdf = PdfSurface::create(sigc::ptr_fun(&test_slot), 1, 1); + pdf->show_page(); + pdf->finish(); + BOOST_CHECK(test_slot_called > 0); +} + +void test_ps_constructor_slot() +{ + test_slot_called = 0; + RefPtr ps = PsSurface::create(sigc::ptr_fun(&test_slot), 1, 1); + ps->show_page(); + ps->finish(); + BOOST_CHECK(test_slot_called > 0); +} + +void test_svg_constructor_slot() +{ + test_slot_called = 0; + RefPtr svg = SvgSurface::create(sigc::ptr_fun(&test_slot), 1, 1); + svg->show_page(); + svg->finish(); + BOOST_CHECK(test_slot_called > 0); +} + +unsigned int test_read_func_called = 0; +static ErrorStatus test_read_func(unsigned char* /*data*/, unsigned int /*len*/) +{ + ++test_read_func_called; + return CAIRO_STATUS_SUCCESS; +} + +unsigned int c_test_read_func_called = 0; +static cairo_status_t c_test_read_func(void* /*closure*/, unsigned char* /*data*/, unsigned int /*len*/) +{ + ++c_test_read_func_called; + return CAIRO_STATUS_SUCCESS; +} + +void test_create_from_png() +{ + // FIXME: these cause a std::bad_alloc exception for some reason + RefPtr surface; + surface = ImageSurface::create_from_png_stream(sigc::ptr_fun(&test_read_func)); + BOOST_CHECK(test_read_func_called > 0); + surface = ImageSurface::create_from_png(&c_test_read_func, NULL); + BOOST_CHECK(c_test_read_func_called > 0); +} + + +test_suite* +init_unit_test_suite(int argc, char* argv[]) +{ + // compile even with -Werror + if (argc && argv) {} + + test_suite* test= BOOST_TEST_SUITE( "Cairo::Surface Tests" ); + + test->add (BOOST_TEST_CASE (&test_write_to_png_stream)); + test->add (BOOST_TEST_CASE (&test_pdf_constructor_slot)); + test->add (BOOST_TEST_CASE (&test_ps_constructor_slot)); + test->add (BOOST_TEST_CASE (&test_svg_constructor_slot)); + test->add (BOOST_TEST_CASE (&test_create_from_png)); + + return test; +} -- cgit v1.2.3