summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathon Jongsma <jjongsma@gnome.org>2008-12-15 00:56:26 -0600
committerJonathon Jongsma <jjongsma@gnome.org>2008-12-15 00:56:26 -0600
commit0fc70d99be2e5377c14853cbe9a6ab7d39c4af63 (patch)
treeefe628e8e548b06ba051b08a960a92df456b3ace
parent3a2c321730e583b6256e43cc91ee71c55b416ee4 (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--.gitignore1
-rw-r--r--ChangeLog9
-rw-r--r--cairomm/fontface.cc6
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/test-font-face.cc245
-rw-r--r--tests/test-user-font.cc333
6 files changed, 346 insertions, 251 deletions
diff --git a/.gitignore b/.gitignore
index f56f7a3..20c26ed 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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-*
diff --git a/ChangeLog b/ChangeLog
index 3dc8b71..fddad41 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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;
+}