diff options
author | Jonathon Jongsma <jjongsma@gnome.org> | 2008-12-08 22:31:56 -0600 |
---|---|---|
committer | Jonathon Jongsma <jjongsma@gnome.org> | 2008-12-08 22:31:56 -0600 |
commit | 3be1dc30c7ff2562eb19bcab278610d44e9ba13c (patch) | |
tree | 9e221351333a4583cc222caa6aae315600d7e777 | |
parent | b1d01ff7dadf2418bb06b3bf58a3847616769e0e (diff) |
UserFontFace redesign to use virtual functions
* cairomm/fontface.cc:
* cairomm/fontface.h: Change UserFontFace implementation to a vfunc-based
implementation rather than requiring people to supply callbacks at runtime as
sigc::slot objects. This was requested by Ian Britten on the mailing list and
was my original plan but ran into issues in my original implementation. This
isn't a fully-working implementation yet, but I think I can overcome the
issues now, so I'm moving forward on the redesign.
* tests/test-font-face.cc: disable UserFontFace tests for now
Conflicts:
ChangeLog
cairomm/fontface.cc
cairomm/fontface.h
-rw-r--r-- | ChangeLog | 11 | ||||
-rw-r--r-- | cairomm/fontface.cc | 156 | ||||
-rw-r--r-- | cairomm/fontface.h | 142 | ||||
-rw-r--r-- | tests/test-font-face.cc | 4 |
4 files changed, 112 insertions, 201 deletions
@@ -1,3 +1,14 @@ +2008-12-07 Jonathon Jongsma <jonathon@quotidian.org> + + * cairomm/fontface.cc: + * cairomm/fontface.h: Change UserFontFace implementation to a vfunc-based + implementation rather than requiring people to supply callbacks at runtime as + sigc::slot objects. This was requested by Ian Britten on the mailing list and + was my original plan but ran into issues in my original implementation. This + isn't a fully-working implementation yet, but I think I can overcome the + issues now, so I'm moving forward on the redesign. + * tests/test-font-face.cc: disable UserFontFace tests for now + 2008-12-05 Jonathon Jongsma <jonathon@quotidian.org> * cairomm/scaledfont.cc: Fix an error in ScaledFont::get_font_face() where diff --git a/cairomm/fontface.cc b/cairomm/fontface.cc index 2246a1b..840a762 100644 --- a/cairomm/fontface.cc +++ b/cairomm/fontface.cc @@ -107,22 +107,13 @@ FontWeight ToyFontFace::get_weight() const //*************************// // UserFont Implementation // //*************************// -//This is defined here, so we can change it later without breaking public ABI. -class UserFontFace::PrivateData -{ -public: - SlotInit m_init_slot; - SlotUnicodeToGlyph m_unicode_to_glyph_slot; - SlotRenderGlyph m_render_glyph_slot; - SlotTextToGlyphs m_text_to_glyphs_slot; -}; static const cairo_user_data_key_t user_font_key = {0}; static void log_uncaught_exception(const char* message = 0) { - std::cerr << "*** cairomm: Uncaught exception in slot callback"; + std::cerr << "*** cairomm: Uncaught exception in UserFont callback"; if(message) std::cerr << ": " << message; @@ -131,8 +122,8 @@ log_uncaught_exception(const char* message = 0) cairo_status_t UserFontFace::init_cb(cairo_scaled_font_t* scaled_font, - cairo_t *cr, - cairo_font_extents_t* metrics) + cairo_t *cr, + cairo_font_extents_t* metrics) { cairo_font_face_t* face = cairo_scaled_font_get_font_face(scaled_font); // we've stored a pointer to the wrapper object in the C object's user_data @@ -140,13 +131,13 @@ UserFontFace::init_cb(cairo_scaled_font_t* scaled_font, static_cast<UserFontFace*>(cairo_font_face_get_user_data(face, &user_font_key)); - if(instance && instance->m_priv && instance->m_priv->m_init_slot) + if(instance) { try { - return (instance->m_priv->m_init_slot)(RefPtr<ScaledFont>(new ScaledFont(scaled_font)), - RefPtr<Context>(new Context(cr)), - static_cast<FontExtents&>(*metrics)); + return instance->init(RefPtr<ScaledFont>(new ScaledFont(scaled_font)), + RefPtr<Context>(new Context(cr)), + static_cast<FontExtents&>(*metrics)); } catch(const std::exception& ex) { @@ -162,22 +153,31 @@ UserFontFace::init_cb(cairo_scaled_font_t* scaled_font, return CAIRO_STATUS_USER_FONT_ERROR; } +ErrorStatus +UserFontFace::init(const RefPtr<ScaledFont>& /*scaled_font*/, + const RefPtr<Context>& /*cr*/, + FontExtents& /*extents*/) +{ + // fallback behavior is to not do anything, just claim success + return CAIRO_STATUS_SUCCESS; +} + cairo_status_t UserFontFace::unicode_to_glyph_cb(cairo_scaled_font_t *scaled_font, - unsigned long unicode, - unsigned long *glyph) + unsigned long unicode, + unsigned long *glyph) { cairo_font_face_t* face = cairo_scaled_font_get_font_face(scaled_font); // we've stored a pointer to the wrapper object in the C object's user_data UserFontFace* instance = static_cast<UserFontFace*>(cairo_font_face_get_user_data(face, &user_font_key)); - if(instance && instance->m_priv && instance->m_priv->m_unicode_to_glyph_slot) + if(instance) { try { - return (instance->m_priv->m_unicode_to_glyph_slot)(RefPtr<ScaledFont>(new ScaledFont(scaled_font)), - unicode, *glyph); + return instance->unicode_to_glyph(RefPtr<ScaledFont>(new ScaledFont(scaled_font)), + unicode, *glyph); } catch(const std::exception& ex) { @@ -193,15 +193,25 @@ UserFontFace::unicode_to_glyph_cb(cairo_scaled_font_t *scaled_font, return CAIRO_STATUS_USER_FONT_ERROR; } +ErrorStatus +UserFontFace::unicode_to_glyph(const RefPtr<ScaledFont>& /*scaled_font*/, + unsigned long unicode, + unsigned long& glyph) +{ + // fallback behavior is just to map 1:1 + glyph = unicode; + return CAIRO_STATUS_SUCCESS; +} + cairo_status_t UserFontFace::text_to_glyphs_cb(cairo_scaled_font_t *scaled_font, - const char *utf8, - int utf8_len, - cairo_glyph_t **glyphs, - int *num_glyphs, - cairo_text_cluster_t **clusters, - int *num_clusters, - cairo_text_cluster_flags_t *cluster_flags) + const char *utf8, + int utf8_len, + cairo_glyph_t **glyphs, + int *num_glyphs, + cairo_text_cluster_t **clusters, + int *num_clusters, + cairo_text_cluster_flags_t *cluster_flags) { cairo_font_face_t* face = cairo_scaled_font_get_font_face(scaled_font); // we've stored a pointer to the wrapper object in the C object's user_data @@ -209,7 +219,7 @@ UserFontFace::text_to_glyphs_cb(cairo_scaled_font_t *scaled_font, static_cast<UserFontFace*>(cairo_font_face_get_user_data(face, &user_font_key)); - if(instance && instance->m_priv && instance->m_priv->m_text_to_glyphs_slot) + if(instance) { try { @@ -219,12 +229,9 @@ UserFontFace::text_to_glyphs_cb(cairo_scaled_font_t *scaled_font, TextClusterFlags local_flags = static_cast<TextClusterFlags>(0); ErrorStatus status = - (instance->m_priv->m_text_to_glyphs_slot)(RefPtr<ScaledFont>(new - ScaledFont(scaled_font)), - utf8_str, - glyph_v, - cluster_v, - local_flags); + instance->text_to_glyphs(RefPtr<ScaledFont>(new + ScaledFont(scaled_font)), + utf8_str, glyph_v, cluster_v, local_flags); // TODO: we re-allocate a new array and pass it back to the caller since // cairo will free the the returned array. It sucks to do this excessive @@ -273,24 +280,36 @@ UserFontFace::text_to_glyphs_cb(cairo_scaled_font_t *scaled_font, return CAIRO_STATUS_USER_FONT_ERROR; } +ErrorStatus +UserFontFace::text_to_glyphs(const RefPtr<ScaledFont>& /*scaled_font*/, + const std::string& /*utf8*/, + std::vector<Glyph>& /*glyphs*/, + std::vector<TextCluster>& /*clusters*/, + TextClusterFlags& /*cluster_flags*/) +{ + // FIXME: default implementation should return -1 for num_glyphs, but there's not + // really any way to do that with the current interface + return CAIRO_STATUS_SUCCESS; +} + cairo_status_t UserFontFace::render_glyph_cb(cairo_scaled_font_t *scaled_font, - unsigned long glyph, - cairo_t *cr, - cairo_text_extents_t *metrics) + unsigned long glyph, + cairo_t *cr, + cairo_text_extents_t *metrics) { cairo_font_face_t* face = cairo_scaled_font_get_font_face(scaled_font); // we've stored a pointer to the wrapper object in the C object's user_data UserFontFace* instance = static_cast<UserFontFace*>(cairo_font_face_get_user_data(face, &user_font_key)); - if(instance && instance->m_priv && instance->m_priv->m_render_glyph_slot) + if(instance) { try { - return (instance->m_priv->m_render_glyph_slot)(RefPtr<ScaledFont>(new ScaledFont(scaled_font)), - glyph, RefPtr<Context>(new Context(cr)), - static_cast<TextExtents&>(*metrics)); + return instance->render_glyph(RefPtr<ScaledFont>(new ScaledFont(scaled_font)), + glyph, RefPtr<Context>(new Context(cr)), + static_cast<TextExtents&>(*metrics)); } catch(const std::exception& ex) { @@ -306,14 +325,11 @@ UserFontFace::render_glyph_cb(cairo_scaled_font_t *scaled_font, return CAIRO_STATUS_USER_FONT_ERROR; } -RefPtr<UserFontFace> UserFontFace::create() -{ - return RefPtr<UserFontFace>(new UserFontFace()); -} +// no default implementation for UserFontFace::render_glyph(), user must +// implement it UserFontFace::UserFontFace() - : FontFace(cairo_user_font_face_create(), true /* has reference */), - m_priv(new PrivateData()) + : FontFace(cairo_user_font_face_create(), true /* has reference */) { check_status_and_throw_exception(cairo_font_face_status(m_cobject)); @@ -322,56 +338,16 @@ UserFontFace::UserFontFace() // can't be a class member), we can get a reference to the wrapper class cairo_font_face_set_user_data(m_cobject, &user_font_key, (void*)this, (cairo_destroy_func_t) NULL); -} - -UserFontFace::~UserFontFace() -{ - delete m_priv; -} - -void UserFontFace::set_init_func(const SlotInit& init_func) -{ - if(!m_priv) - return; - - // copy the new slot - m_priv->m_init_slot = init_func; - - // register it with cairo cairo_user_font_face_set_init_func(cobj(), init_cb); -} - -void UserFontFace::set_render_glyph_func(const SlotRenderGlyph& render_glyph_func) -{ - if(!m_priv) - return; - - // copy the slot - m_priv->m_render_glyph_slot = render_glyph_func; cairo_user_font_face_set_render_glyph_func(cobj(), render_glyph_cb); -} - -void UserFontFace::set_unicode_to_glyph_func(const SlotUnicodeToGlyph& unicode_to_glyph_func) -{ - if(!m_priv) - return; - - // copy the slot - m_priv->m_unicode_to_glyph_slot = unicode_to_glyph_func; cairo_user_font_face_set_unicode_to_glyph_func(cobj(), unicode_to_glyph_cb); + cairo_user_font_face_set_text_to_glyphs_func(cobj(), text_to_glyphs_cb); } -void UserFontFace::set_text_to_glyphs_func(const SlotTextToGlyphs& text_to_glyphs_func) +UserFontFace::~UserFontFace() { - if(!m_priv) - return; - - // copy the slot - m_priv->m_text_to_glyphs_slot = text_to_glyphs_func; - cairo_user_font_face_set_text_to_glyphs_func(cobj(), text_to_glyphs_cb); } - #ifdef CAIRO_HAS_FT_FONT RefPtr<FtFontFace> diff --git a/cairomm/fontface.h b/cairomm/fontface.h index 810f404..5001e28 100644 --- a/cairomm/fontface.h +++ b/cairomm/fontface.h @@ -33,7 +33,6 @@ /* end OS X */ -#include <sigc++/slot.h> #include <cairo.h> #ifdef CAIRO_HAS_FT_FONT #include <cairo-ft.h> @@ -157,7 +156,12 @@ public: virtual ~UserFontFace(); + /* static RefPtr<UserFontFace> create(); + static RefPtr<UserFontFace> create(cairo_font_face_t* cobject, bool has_reference = false); + */ + +protected: /** A SlotInit slot is called when a ScaledFont needs * to be created for a UserFontFace. @@ -190,32 +194,12 @@ public: * @param extents font extents to fill in, in font space. * @return CAIRO_STATUS_SUCCESS upon success, or CAIRO_STATUS_USER_FONT_ERROR or any other error status on error. */ - typedef sigc::slot<ErrorStatus, - const RefPtr<ScaledFont>&, - const RefPtr<Context>&, - FontExtents&> SlotInit; - - /** Sets the scaled-font initialization function of a user-font. - * See SlotInit for details of how the callback works. - * - * The font-face should not be immutable or a CAIRO_STATUS_USER_FONT_IMMUTABLE - * error will occur. A user font-face is immutable as soon as a scaled-font - * is created from it. - * - * @param init_func The init callback. - * - * @since 1.8 - */ - void set_init_func(const SlotInit& init_func); + virtual ErrorStatus init(const RefPtr<ScaledFont>& scaled_font, + const RefPtr<Context>& cr, + FontExtents& extents); - /** A SlotUnicodeToGlyph slot is called to convert an - * input Unicode character to a single glyph. This is used by the - * Context::show_text() operation. - * - * For example: - * <code> - * ErrorStatus my_unicode_to_glyph_func(const RefPtr<ScaledFont>& scaled_font, unsigned long unicode, unsigned long& glyph); - * </code> + /** unicode_to_glyph is called to convert an input Unicode character to a + * single glyph. This is used by the Context::show_text() operation. * * This callback is used to provide the same functionality as the * text_to_glyphs callback does (see SlotTextToGlyphs) but has much less @@ -242,34 +226,12 @@ public: * @return CAIRO_STATUS_SUCCESS upon success, or CAIRO_STATUS_USER_FONT_ERROR * or any other error status on error. */ - typedef sigc::slot<ErrorStatus, - const RefPtr<ScaledFont>&, - unsigned long /*unicode*/, - unsigned long& /*glyph*/> SlotUnicodeToGlyph; - - - /** Sets the unicode-to-glyph conversion function of a user-font. - * See SlotUnicodeToGlyph for details of how the callback - * works. - * - * The font-face should not be immutable or a CAIRO_STATUS_USER_FONT_IMMUTABLE - * error will occur. A user font-face is immutable as soon as a scaled-font - * is created from it. - * - * @param unicode_to_glyph_func The unicode_to_glyph callback. - * - * @since 1.8 - */ - void set_unicode_to_glyph_func(const SlotUnicodeToGlyph& unicode_to_glyph_func); + virtual ErrorStatus unicode_to_glyph(const RefPtr<ScaledFont>& scaled_font, + unsigned long unicode, + unsigned long& glyph); - /** A SlotRenderGlyph slot is called when a user - * ScaledFont needs to render a glyph. - * - * For example: - * <code> - * ErrorStatus my_render_glyph_func(const RefPtr<ScaledFont>& scaled_font, unsigned long glyph, const RefPtr<Context>& cr, TextExtents& metrics); - * </code> + /** render_glyph is called when a user ScaledFont needs to render a glyph. * * The callback is mandatory, and expected to draw the glyph with code glyph * to the Context cr. cr is prepared such that the glyph drawing is done @@ -301,47 +263,28 @@ public: * @param glyph glyph code to render. * @param cr cairo context to draw to, in font space. * @param extents glyph extents to fill in, in font space. - * @return CAIRO_STATUS_SUCCESS upon success, or CAIRO_STATUS_USER_FONT_ERROR or any other error status on error. - */ - typedef sigc::slot<ErrorStatus, - const RefPtr<ScaledFont>&, - unsigned long /*glyph*/, - const RefPtr<Context>&, - TextExtents& /*metrics*/> SlotRenderGlyph; - - /** Sets the glyph rendering function of a user-font. - * See SlotRenderGlyph for details of how the callback - * works. - * - * The font-face should not be immutable or a CAIRO_STATUS_USER_FONT_IMMUTABLE - * error will occur. A user font-face is immutable as soon as a scaled-font - * is created from it. - * - * The render_glyph callback is the only mandatory callback of a user-font. - * If the callback is %NULL and a glyph is tried to be rendered using - * @font_face, a CAIRO_STATUS_USER_FONT_ERROR will occur. - * - * @param render_glyph_func The render_glyph callback. - * - * @since 1.8 + * @return CAIRO_STATUS_SUCCESS upon success, or CAIRO_STATUS_USER_FONT_ERROR + * or any other error status on error. */ - void set_render_glyph_func(const SlotRenderGlyph& render_glyph_func); + virtual ErrorStatus render_glyph(const RefPtr<ScaledFont>& scaled_font, + unsigned long glyph, + const RefPtr<Context>& cr, + TextExtents& metrics) = 0; - /** A SlotTextToGlyphs slot is called to convert input text to an array of glyphs. This is used by the - * Cairo::Context::show_text() operation. + /** text_to_glyphs is called to convert input text to an array of glyphs. This + * is used by the Cairo::Context::show_text() operation. * - * Using this callback the user-font has full control on glyphs and their + * By implementing this virtual function the user-font has full control on glyphs and their * positions. That means, it allows for features like ligatures and kerning, * as well as complex <firstterm>shaping</firstterm> required for scripts like * Arabic and Indic. * - * The callback should populate the glyph indices and - * positions (in font space) assuming that the text is to be shown at the - * origin. + * This virtual function should populate the glyph indices and positions (in + * font space) assuming that the text is to be shown at the origin. * * The callback is optional. If not set, the unicode_to_glyph callback - * is tried. See SlotUnicodeToGlyph. + * is tried. * * Note: While cairo does not impose any limitation on glyph indices, * some applications may assume that a glyph index fits in a 16-bit @@ -361,40 +304,17 @@ public: * * Since: 1.8 **/ - typedef sigc::slot<ErrorStatus, - const RefPtr<ScaledFont>&, - const std::string& /*utf8*/, - std::vector<Glyph>& /*glyphs*/, - std::vector<TextCluster>& /*clusters*/, - TextClusterFlags& /*cluster_flags*/> SlotTextToGlyphs; - - /** Sets the text-to-glyphs conversion function of a user-font. - * See SlotTextToGlyphs for details of how the callback - * works. - * - * The font-face should not be immutable or a CAIRO_STATUS_USER_FONT_IMMUTABLE - * error will occur. A user font-face is immutable as soon as a scaled-font - * is created from it. - * - * @param text_to_glyphs_func The text_to_glyphs callback. - * - * @since 1.8 - */ - void set_text_to_glyphs_func(const SlotTextToGlyphs& text_to_glyphs_func); + 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); - // Like gtkmm, we don't have get_*_func() methods. They would not be very useful. - //TODO: Add unset_*_func() methods, to match the use of NULL in the C API? - - -protected: UserFontFace(); private: - struct PrivateData; - PrivateData* m_priv; - static cairo_status_t init_cb(cairo_scaled_font_t* scaled_font, cairo_t *cr, diff --git a/tests/test-font-face.cc b/tests/test-font-face.cc index 0ebe91e..85ccccf 100644 --- a/tests/test-font-face.cc +++ b/tests/test-font-face.cc @@ -46,6 +46,7 @@ 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(); @@ -280,6 +281,7 @@ void test_user_font_replace_callback() 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() @@ -344,12 +346,14 @@ 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 |