diff options
author | Jonathon Jongsma <jjongsma@gnome.org> | 2008-12-15 00:56:26 -0600 |
---|---|---|
committer | Jonathon Jongsma <jjongsma@gnome.org> | 2008-12-15 00:56:26 -0600 |
commit | 0fc70d99be2e5377c14853cbe9a6ab7d39c4af63 (patch) | |
tree | efe628e8e548b06ba051b08a960a92df456b3ace | |
parent | 3a2c321730e583b6256e43cc91ee71c55b416ee4 (diff) |
Add tests and fix a bug in UserFontFace
* cairomm/fontface.cc: fixed a bug in UserFont where I was incorrectly using a
function static variable and so it was not returning negative numbers for
num_glyphs when I expected it to
* tests/Makefile.am:
* tests/test-font-face.cc:
* tests/test-user-font.cc: Added tests for UserFontFace
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | cairomm/fontface.cc | 6 | ||||
-rw-r--r-- | tests/Makefile.am | 3 | ||||
-rw-r--r-- | tests/test-font-face.cc | 245 | ||||
-rw-r--r-- | tests/test-user-font.cc | 333 |
6 files changed, 346 insertions, 251 deletions
@@ -58,6 +58,7 @@ tests/test-surface tests/test-scaled-font tests/test-font-options tests/test-matrix +tests/test-user-font cairomm/cairommconfig.h* cairomm/stamp-* @@ -1,5 +1,14 @@ 2008-12-14 Jonathon Jongsma <jonathon@quotidian.org> + * cairomm/fontface.cc: fixed a bug in UserFont where I was incorrectly using a + function static variable and so it was not returning negative numbers for + num_glyphs when I expected it to + * tests/Makefile.am: + * tests/test-font-face.cc: + * tests/test-user-font.cc: Added tests for UserFontFace + +2008-12-14 Jonathon Jongsma <jonathon@quotidian.org> + * cairomm/scaledfont.cc: actually fix a reference-counting issue with ScaledFont::get_font_face() that I thought I had fixed in b1d01ff7 * tests/test-scaled-font.cc: add a test for the get_font_face() bug diff --git a/cairomm/fontface.cc b/cairomm/fontface.cc index 2d305bf..0ffa5c3 100644 --- a/cairomm/fontface.cc +++ b/cairomm/fontface.cc @@ -309,11 +309,7 @@ UserFontFace::text_to_glyphs(const RefPtr<ScaledFont>& /*scaled_font*/, // bool value in the user_data, which we can read back in the // text_to_glyphs_cb and used as a signal to return -1 for the num_glyphs // parameter. - static bool first_time = true; - if (first_time) { - cairo_font_face_set_user_data(cobj(), &USER_DATA_KEY_DEFAULT_TEXT_TO_GLYPHS, reinterpret_cast<void*>(true), NULL); - first_time = false; - } + cairo_font_face_set_user_data(cobj(), &USER_DATA_KEY_DEFAULT_TEXT_TO_GLYPHS, reinterpret_cast<void*>(true), NULL); return CAIRO_STATUS_SUCCESS; } diff --git a/tests/Makefile.am b/tests/Makefile.am index 250d60c..c18d975 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,10 +1,11 @@ if AUTOTESTS # build automated 'tests' -TESTS=test-context test-font-face test-surface test-scaled-font test-font-options test-matrix +TESTS=test-context test-font-face test-surface test-scaled-font test-font-options test-matrix test-user-font noinst_PROGRAMS = $(TESTS) test_context_SOURCES=test-context.cc test_font_face_SOURCES=test-font-face.cc +test_user_font_SOURCES=test-user-font.cc test_surface_SOURCES=test-surface.cc test_scaled_font_SOURCES=test-scaled-font.cc test_font_options_SOURCES=test-font-options.cc diff --git a/tests/test-font-face.cc b/tests/test-font-face.cc index 85ccccf..466f408 100644 --- a/tests/test-font-face.cc +++ b/tests/test-font-face.cc @@ -46,243 +46,6 @@ void test_toy_getters () BOOST_CHECK_EQUAL (Cairo::FONT_TYPE_TOY, toy->get_type()); } -#if 0 -void test_user_font_create() -{ - Cairo::RefPtr<Cairo::UserFontFace> font = Cairo::UserFontFace::create(); - BOOST_CHECK_EQUAL (Cairo::FONT_TYPE_USER, font->get_type()); -} - -// create some dummy callbacks -static unsigned int init_call_count = 0; -Cairo::ErrorStatus my_init(const Cairo::RefPtr<Cairo::ScaledFont>&, const Cairo::RefPtr<Cairo::Context>&, Cairo::FontExtents&) -{ - init_call_count++; - return CAIRO_STATUS_SUCCESS; -} - -static unsigned int unicode_to_glyph_call_count = 0; -Cairo::ErrorStatus my_unicode_to_glyph(const Cairo::RefPtr<Cairo::ScaledFont>&, unsigned long, unsigned long&) -{ - unicode_to_glyph_call_count++; - return CAIRO_STATUS_SUCCESS; -} - -static unsigned int render_glyph_call_count = 0; -Cairo::ErrorStatus my_render_glyph(const Cairo::RefPtr<Cairo::ScaledFont>&, unsigned long, const Cairo::RefPtr<Cairo::Context>&, Cairo::TextExtents&) -{ - render_glyph_call_count++; - return CAIRO_STATUS_SUCCESS; -} - -static unsigned int text_to_glyphs_call_count = 0; -Cairo::ErrorStatus my_text_to_glyphs(const Cairo::RefPtr<Cairo::ScaledFont>&, const std::string& utf8, std::vector<Cairo::Glyph>& glyphs, std::vector<Cairo::TextCluster>& /*clusters*/, Cairo::TextClusterFlags& /*cluster_flags*/) -{ - text_to_glyphs_call_count++; - if (glyphs.size()) - glyphs.clear(); - // just fill in some bogus glyph indexes - std::string::const_iterator str_iter = utf8.begin(); - for (; str_iter != utf8.end(); ++str_iter) - { - Cairo::Glyph g; - g.index = (unsigned long) *str_iter; - glyphs.push_back(g); - } - return CAIRO_STATUS_SUCCESS; -} - -void test_user_font_callbacks_ptr() -{ - render_glyph_call_count = 0; - unicode_to_glyph_call_count = 0; - init_call_count = 0; - Cairo::RefPtr<Cairo::UserFontFace> font = Cairo::UserFontFace::create(); - BOOST_CHECK(font); - font->set_init_func(sigc::ptr_fun(my_init)); - font->set_unicode_to_glyph_func(sigc::ptr_fun(my_unicode_to_glyph)); - font->set_render_glyph_func(sigc::ptr_fun(my_render_glyph)); - Cairo::RefPtr<Cairo::ScaledFont> scaled_font = - Cairo::ScaledFont::create(font, Cairo::scaled_matrix(10, 10), Cairo::identity_matrix(), - Cairo::FontOptions()); - BOOST_CHECK (init_call_count > 0); - Cairo::RefPtr<Cairo::ImageSurface> surface = - Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, 100, 100); - Cairo::RefPtr<Cairo::Context> cr = Cairo::Context::create(surface); - cr->set_font_face(font); - cr->show_text("Hello, world"); - BOOST_CHECK (unicode_to_glyph_call_count > 0); - BOOST_CHECK (render_glyph_call_count > 0); -} - -// since unicode_to_glyph_func and text_to_glyphs_func are mutually exclusive, -// we must test them separately. This test tests the text_to_glyphs_func -void test_user_font_callbacks_ptr_text() -{ - render_glyph_call_count = 0; - text_to_glyphs_call_count = 0; - init_call_count = 0; - Cairo::RefPtr<Cairo::UserFontFace> font = Cairo::UserFontFace::create(); - BOOST_CHECK(font); - font->set_init_func(sigc::ptr_fun(my_init)); - font->set_render_glyph_func(sigc::ptr_fun(my_render_glyph)); - font->set_text_to_glyphs_func(sigc::ptr_fun(my_text_to_glyphs)); - Cairo::RefPtr<Cairo::ScaledFont> scaled_font = - Cairo::ScaledFont::create(font, Cairo::scaled_matrix(10, 10), Cairo::identity_matrix(), - Cairo::FontOptions()); - BOOST_CHECK (init_call_count > 0); - Cairo::RefPtr<Cairo::ImageSurface> surface = - Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, 100, 100); - Cairo::RefPtr<Cairo::Context> cr = Cairo::Context::create(surface); - cr->set_font_face(font); - cr->show_text("Hello, world"); - BOOST_CHECK (render_glyph_call_count > 0); - BOOST_CHECK (text_to_glyphs_call_count > 0); -} - -struct UserFontCallbacks -{ -Cairo::ErrorStatus init(const Cairo::RefPtr<Cairo::ScaledFont>&, const Cairo::RefPtr<Cairo::Context>&, Cairo::FontExtents&) -{ - init_call_count++; - return CAIRO_STATUS_SUCCESS; -} - -Cairo::ErrorStatus unicode_to_glyph(const Cairo::RefPtr<Cairo::ScaledFont>&, unsigned long, unsigned long&) -{ - unicode_to_glyph_call_count++; - return CAIRO_STATUS_SUCCESS; -} - -Cairo::ErrorStatus render_glyph(const Cairo::RefPtr<Cairo::ScaledFont>&, unsigned long, const Cairo::RefPtr<Cairo::Context>&, Cairo::TextExtents&) -{ - render_glyph_call_count++; - return CAIRO_STATUS_SUCCESS; -} - -static unsigned int init_call_count; -static unsigned int unicode_to_glyph_call_count; -static unsigned int render_glyph_call_count; -}; - -unsigned int UserFontCallbacks::init_call_count = 0; -unsigned int UserFontCallbacks::unicode_to_glyph_call_count = 0; -unsigned int UserFontCallbacks::render_glyph_call_count = 0; - -void test_user_font_callbacks_mem() -{ - Cairo::RefPtr<Cairo::UserFontFace> font = Cairo::UserFontFace::create(); - BOOST_CHECK(font); - UserFontCallbacks callbacks; - font->set_init_func(sigc::mem_fun(&callbacks, &UserFontCallbacks::init)); - font->set_unicode_to_glyph_func(sigc::mem_fun(&callbacks, - &UserFontCallbacks::unicode_to_glyph)); - font->set_render_glyph_func(sigc::mem_fun(&callbacks, - &UserFontCallbacks::render_glyph)); - Cairo::RefPtr<Cairo::ScaledFont> scaled_font = - Cairo::ScaledFont::create(font, Cairo::scaled_matrix(10, 10), Cairo::identity_matrix(), - Cairo::FontOptions()); - BOOST_CHECK (UserFontCallbacks::init_call_count > 0); - Cairo::RefPtr<Cairo::ImageSurface> surface = - Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, 100, 100); - Cairo::RefPtr<Cairo::Context> cr = Cairo::Context::create(surface); - cr->set_font_face(font); - cr->show_text("Hello, world"); - BOOST_CHECK (UserFontCallbacks::unicode_to_glyph_call_count > 0); - BOOST_CHECK (UserFontCallbacks::render_glyph_call_count > 0); -} - -static unsigned int init_exception_call_count = 0; -Cairo::ErrorStatus my_init_exception(const Cairo::RefPtr<Cairo::ScaledFont>&, const Cairo::RefPtr<Cairo::Context>&, Cairo::FontExtents&) -{ - init_exception_call_count++; - throw std::logic_error("init exception"); -} - -static unsigned int unicode_to_glyph_exception_call_count = 0; -Cairo::ErrorStatus my_unicode_to_glyph_exception(const Cairo::RefPtr<Cairo::ScaledFont>&, unsigned long, unsigned long&) -{ - unicode_to_glyph_exception_call_count++; - throw std::logic_error("unicode-to-glyph exception"); -} - -static unsigned int render_glyph_exception_call_count = 0; -Cairo::ErrorStatus my_render_glyph_exception(const Cairo::RefPtr<Cairo::ScaledFont>&, unsigned long, const Cairo::RefPtr<Cairo::Context>&, Cairo::TextExtents&) -{ - render_glyph_exception_call_count++; - throw std::logic_error("render-glyph exception"); -} - - -void test_user_font_callbacks_exception() -{ - Cairo::RefPtr<Cairo::UserFontFace> font = Cairo::UserFontFace::create(); - BOOST_CHECK(font); - font->set_init_func(sigc::ptr_fun(my_init_exception)); - - // the init() callback will throw an exception, if this isn't handled in the - // callback wrapper, the program will abort since an exception can't unwind - // through C code. However, due to the exception being thrown, the create() - // function will fail and throw a new exception. So if the executable doesn't - // abort, we should get an exception here. - Cairo::RefPtr<Cairo::ScaledFont> scaled_font; - BOOST_CHECK_THROW (scaled_font = Cairo::ScaledFont::create(font, - Cairo::scaled_matrix(10, 10), - Cairo::identity_matrix(), - Cairo::FontOptions()), - Cairo::logic_error); - BOOST_CHECK (init_exception_call_count > 0); - - // now initialize a scaled font properly so we can test the other callbacks - font = Cairo::UserFontFace::create(); - font->set_init_func(sigc::ptr_fun(my_init)); - font->set_render_glyph_func(sigc::ptr_fun(my_render_glyph_exception)); - font->set_unicode_to_glyph_func(sigc::ptr_fun(my_unicode_to_glyph_exception)); - BOOST_CHECK_NO_THROW (scaled_font = Cairo::ScaledFont::create(font, - Cairo::scaled_matrix(10, 10), - Cairo::identity_matrix(), - Cairo::FontOptions())) - Cairo::RefPtr<Cairo::ImageSurface> surface = - Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, 100, 100); - Cairo::RefPtr<Cairo::Context> cr = Cairo::Context::create(surface); - cr->set_font_face(font); - // this call should throw an exception since the callback wrapper will return - // an error status (that will be translated into an exception) but the test - // shouldn't abort sindce the callback exceptions are handled by the callback - // wrapper - BOOST_REQUIRE_EQUAL (CAIRO_STATUS_SUCCESS, font->get_status()); - BOOST_CHECK_THROW(cr->show_text("Hello, world"), Cairo::logic_error); - BOOST_CHECK (UserFontCallbacks::unicode_to_glyph_call_count > 0); - BOOST_CHECK (UserFontCallbacks::render_glyph_call_count > 0); -} - -// create some dummy callbacks -static unsigned int init2_call_count = 0; -Cairo::ErrorStatus my_init2(const Cairo::RefPtr<Cairo::ScaledFont>&, const Cairo::RefPtr<Cairo::Context>&, Cairo::FontExtents&) -{ - init2_call_count++; - return CAIRO_STATUS_SUCCESS; -} - -void test_user_font_replace_callback() -{ - // reset - init_call_count = 0; - Cairo::RefPtr<Cairo::UserFontFace> font = Cairo::UserFontFace::create(); - font->set_init_func(sigc::ptr_fun(my_init)); - // now replace the init function with my_init2 and make sure that the 2nd - // function is called, not the first - font->set_init_func(sigc::ptr_fun(my_init2)); - Cairo::RefPtr<Cairo::ScaledFont> scaled_font; - BOOST_CHECK_NO_THROW (scaled_font = Cairo::ScaledFont::create(font, - Cairo::scaled_matrix(10, 10), - Cairo::identity_matrix(), - Cairo::FontOptions())) - BOOST_CHECK (init2_call_count > 0); - BOOST_CHECK_EQUAL (init_call_count, 0); -} -#endif // UserFont disabled - #ifdef CAIRO_HAS_FT_FONT void test_ft_font_face() { @@ -346,14 +109,6 @@ init_unit_test_suite(int argc, char* argv[]) test->add (BOOST_TEST_CASE (&test_create_toy)); test->add (BOOST_TEST_CASE (&test_toy_getters)); - /* - test->add (BOOST_TEST_CASE (&test_user_font_create)); - test->add (BOOST_TEST_CASE (&test_user_font_callbacks_ptr)); - test->add (BOOST_TEST_CASE (&test_user_font_callbacks_ptr_text)); - test->add (BOOST_TEST_CASE (&test_user_font_callbacks_mem)); - test->add (BOOST_TEST_CASE (&test_user_font_callbacks_exception)); - test->add (BOOST_TEST_CASE (&test_user_font_replace_callback)); - */ #ifdef CAIRO_HAS_FT_FONT test->add (BOOST_TEST_CASE (&test_ft_font_face)); #endif // CAIRO_HAS_FT_FONT diff --git a/tests/test-user-font.cc b/tests/test-user-font.cc new file mode 100644 index 0000000..a7d9647 --- /dev/null +++ b/tests/test-user-font.cc @@ -0,0 +1,333 @@ +// vim: ts=2 sw=2 et +/* + * These tests are of limited usefulness. In fact, you might even say that + * they're not really tests at all. But I felt that it would be useful to have + * some basic usage of most functions just to verify that things compile and + * work generally + */ + +#include <cfloat> +#include <stdexcept> +#include <boost/test/unit_test.hpp> +#include <boost/test/test_tools.hpp> +#include <boost/test/floating_point_comparison.hpp> +using namespace boost::unit_test; +#include <cairomm/fontface.h> +#include <cairomm/scaledfont.h> +#include <cairomm/surface.h> +#include <cairomm/context.h> + +using namespace Cairo; + +// little utility helper classes +struct TestSetup +{ + TestSetup() + { + surface = ImageSurface::create(Cairo::FORMAT_ARGB32, 100, 100); + cr = Cairo::Context::create(surface); + } + + RefPtr<Context> cr; + RefPtr<Surface> surface; +}; + +// a no-op-render user font base class +class NullRenderUserFont : public UserFontFace +{ +public: + ErrorStatus + render_glyph(const RefPtr<ScaledFont>& /*scaled_font*/, + unsigned long /*glyph*/, + const RefPtr<Context>& /*cr*/, + TextExtents& /*metrics*/) + { ++count_render_glyph; return CAIRO_STATUS_SUCCESS; } + + int count_render_glyph; + +protected: + NullRenderUserFont() : UserFontFace(), count_render_glyph(0) {} +}; + +/****************************** + * test_implement_text + ******************************/ +class ImplTextUserFont: public NullRenderUserFont +{ +public: + static RefPtr<ImplTextUserFont> create() { return RefPtr<ImplTextUserFont>(new ImplTextUserFont());}; + virtual ErrorStatus text_to_glyphs(const RefPtr<ScaledFont>& /*scaled_font*/, + const std::string& /*utf8*/, + std::vector<Glyph>& glyphs, + std::vector<TextCluster>& /*clusters*/, + TextClusterFlags& /*cluster_flags*/) + { + ++count_text_to_glyphs; + // return an arbitrary glyph + Glyph g = {84, 0, 0}; + glyphs.push_back(g); + return CAIRO_STATUS_SUCCESS; + } + int count_text_to_glyphs; + +protected: + ImplTextUserFont() : count_text_to_glyphs(0) {} +}; + +void test_implement_text() +{ + TestSetup setup; + RefPtr<ImplTextUserFont> font = ImplTextUserFont::create(); + setup.cr->set_font_face(font); + setup.cr->show_text("hello"); + BOOST_REQUIRE(font->count_text_to_glyphs > 0); + BOOST_REQUIRE(font->count_render_glyph > 0); +} + +/****************************** + * test_implement_unicode + ******************************/ +class ImplUnicodeUserFont: public NullRenderUserFont +{ +public: + static RefPtr<ImplUnicodeUserFont> create() { return RefPtr<ImplUnicodeUserFont>(new ImplUnicodeUserFont());}; + virtual ErrorStatus unicode_to_glyph(const RefPtr<ScaledFont>& /*scaled_font*/, + unsigned long /*unicode*/, + unsigned long& /*glyph*/) + { ++count_unicode_to_glyph; return CAIRO_STATUS_SUCCESS;} + int count_unicode_to_glyph; + +protected: + ImplUnicodeUserFont() : NullRenderUserFont(), count_unicode_to_glyph(0) {} +}; + +void test_implement_unicode() +{ + TestSetup setup; + RefPtr<ImplTextUserFont> font = ImplTextUserFont::create(); + setup.cr->set_font_face(font); + setup.cr->show_text("hello"); + BOOST_REQUIRE(font->count_text_to_glyphs > 0); + BOOST_REQUIRE(font->count_render_glyph > 0); +} + +/****************************** + * test_implement_both + ******************************/ +class ImplBothUserFont: public NullRenderUserFont +{ +public: + static RefPtr<ImplBothUserFont> create() { return RefPtr<ImplBothUserFont>(new ImplBothUserFont());}; + virtual ErrorStatus unicode_to_glyph(const RefPtr<ScaledFont>& /*scaled_font*/, + unsigned long /*unicode*/, + unsigned long& /*glyph*/) + { ++count_unicode_to_glyph; return CAIRO_STATUS_SUCCESS;} + int count_unicode_to_glyph; + + virtual ErrorStatus text_to_glyphs(const RefPtr<ScaledFont>& /*scaled_font*/, + const std::string& /*utf8*/, + std::vector<Glyph>& glyphs, + std::vector<TextCluster>& /*clusters*/, + TextClusterFlags& /*cluster_flags*/) + { + ++count_text_to_glyphs; + // return an arbitrary glyph + Glyph g = {84, 0, 0}; + glyphs.push_back(g); + return CAIRO_STATUS_SUCCESS; + } + int count_text_to_glyphs; + +protected: + ImplBothUserFont() : NullRenderUserFont(), count_unicode_to_glyph(0), + count_text_to_glyphs(0) {} +}; + +void test_implement_both() +{ + TestSetup setup; + RefPtr<ImplBothUserFont> font = ImplBothUserFont::create(); + setup.cr->set_font_face(font); + setup.cr->show_text("hello"); + // text_to_glyphs should take precedence + BOOST_REQUIRE(font->count_text_to_glyphs > 0); + BOOST_REQUIRE(font->count_unicode_to_glyph == 0); + BOOST_REQUIRE(font->count_render_glyph > 0); +} + +/****************************** + * test_implement_neither + ******************************/ +class ImplNeitherUserFont: public NullRenderUserFont +{ +public: + static RefPtr<ImplNeitherUserFont> create() { return RefPtr<ImplNeitherUserFont>(new ImplNeitherUserFont());}; + +protected: + ImplNeitherUserFont() : NullRenderUserFont() {} +}; + +void test_implement_neither() +{ + TestSetup setup; + RefPtr<ImplNeitherUserFont> font = ImplNeitherUserFont::create(); + setup.cr->set_font_face(font); + setup.cr->show_text("hello"); + BOOST_REQUIRE(font->count_render_glyph > 0); +} + +/****************************** + * test_implement_init + ******************************/ +class ImplInitUserFont: public NullRenderUserFont +{ +public: + static RefPtr<ImplInitUserFont> create() { return RefPtr<ImplInitUserFont>(new ImplInitUserFont());}; + ErrorStatus init(const RefPtr<ScaledFont>& /*scaled_font*/, + const RefPtr<Context>& /*cr*/, + FontExtents& /*extents*/) + {++count_init; return CAIRO_STATUS_SUCCESS;} + + int count_init; + +protected: + ImplInitUserFont() : NullRenderUserFont(), count_init(0) {} +}; + +void test_implement_init() +{ + TestSetup setup; + RefPtr<ImplInitUserFont> font = ImplInitUserFont::create(); + setup.cr->set_font_face(font); + setup.cr->show_text("hello"); + BOOST_REQUIRE(font->count_init > 0); + BOOST_REQUIRE(font->count_render_glyph > 0); +} + +class ExceptionUserFont : public UserFontFace +{ +public: + static RefPtr<ExceptionUserFont> create(int flags) { return RefPtr<ExceptionUserFont>(new ExceptionUserFont(flags));}; + + ErrorStatus + render_glyph(const RefPtr<ScaledFont>& /*scaled_font*/, + unsigned long /*glyph*/, + const RefPtr<Context>& /*cr*/, + TextExtents& /*metrics*/) + { + count_render_glyph++; + if (m_flags & FLAG_RENDER) + throw std::logic_error("render-glyph exception"); + return CAIRO_STATUS_SUCCESS; + } + + ErrorStatus + unicode_to_glyph(const RefPtr<ScaledFont>& /*scaled_font*/, + unsigned long unicode, + unsigned long& glyph) + { + count_unicode_to_glyph++; + if (m_flags & FLAG_UNICODE) + throw std::logic_error("unicode-to-glyph exception"); + + glyph = unicode; + return CAIRO_STATUS_SUCCESS; + } + + ErrorStatus + init(const RefPtr<ScaledFont>& /*scaled_font*/, + const RefPtr<Context>& /*cr*/, + FontExtents& /*extents*/) + { + count_init++; + if (m_flags & FLAG_INIT) + throw std::logic_error("init exception"); + return CAIRO_STATUS_SUCCESS; + } + + int count_render_glyph; + int count_text_to_glyphs; + int count_unicode_to_glyph; + int count_init; + int m_flags; + + static const int FLAG_INIT = 1 << 0; + static const int FLAG_UNICODE = 1 << 1; + static const int FLAG_RENDER = 1 << 2; + +protected: + ExceptionUserFont(int flags) : UserFontFace(), count_render_glyph(0), + count_text_to_glyphs(0), count_unicode_to_glyph(0), count_init(0), + m_flags(flags) {} +}; + +void test_user_font_exception() +{ + Cairo::RefPtr<ExceptionUserFont> font = + ExceptionUserFont::create(ExceptionUserFont::FLAG_INIT); + BOOST_CHECK(font); + + // the init() callback will throw an exception, if this isn't handled in the + // callback wrapper, the program will abort since an exception can't unwind + // through C code. However, due to the exception being thrown, the create() + // function will fail and throw a new exception. So if the executable doesn't + // abort, we should get an exception here. + Cairo::RefPtr<Cairo::ScaledFont> scaled_font; + BOOST_CHECK_THROW (scaled_font = Cairo::ScaledFont::create(font, + Cairo::scaled_matrix(10, 10), + Cairo::identity_matrix(), + Cairo::FontOptions()), + Cairo::logic_error); + BOOST_CHECK (font->count_init > 0); + + // now test when an exception is thrown in unicode_to_glyph + font = ExceptionUserFont::create(ExceptionUserFont::FLAG_UNICODE); + BOOST_CHECK_NO_THROW (scaled_font = Cairo::ScaledFont::create(font, + Cairo::scaled_matrix(10, 10), + Cairo::identity_matrix(), + Cairo::FontOptions())); + TestSetup setup; + setup.cr->set_font_face(font); + // this call should throw an exception since the callback wrapper will return + // an error status (that will be translated into an exception) but the test + // shouldn't abort since the callback exceptions are handled by the callback + // wrapper + BOOST_REQUIRE_EQUAL (CAIRO_STATUS_SUCCESS, font->get_status()); + BOOST_CHECK_THROW(setup.cr->show_text("Hello, world"), Cairo::logic_error); + BOOST_CHECK(font->count_unicode_to_glyph > 0); + BOOST_CHECK_EQUAL(font->count_render_glyph, 0); + + // now test when an exception is thrown in render_glyph + font = ExceptionUserFont::create(ExceptionUserFont::FLAG_RENDER); + BOOST_CHECK_NO_THROW (scaled_font = Cairo::ScaledFont::create(font, + Cairo::scaled_matrix(10, 10), + Cairo::identity_matrix(), + Cairo::FontOptions())); + // need a new setup since the old cr is now in an error state, so attemtping + // to use it will throw an exception + TestSetup setup2; + BOOST_CHECK_NO_THROW(setup2.cr->set_font_face(font)); + BOOST_REQUIRE_EQUAL (CAIRO_STATUS_SUCCESS, font->get_status()); + BOOST_CHECK_THROW(setup2.cr->show_text("Hello, world"), Cairo::logic_error); + BOOST_CHECK (font->count_unicode_to_glyph > 0); + BOOST_CHECK (font->count_render_glyph > 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::UserFontFace Tests" ); + + test->add (BOOST_TEST_CASE (&test_implement_text)); + test->add (BOOST_TEST_CASE (&test_implement_unicode)); + test->add (BOOST_TEST_CASE (&test_implement_both)); + test->add (BOOST_TEST_CASE (&test_implement_neither)); + test->add (BOOST_TEST_CASE (&test_implement_init)); + test->add (BOOST_TEST_CASE (&test_user_font_exception)); + + return test; +} |