diff options
author | Murray Cumming <murrayc@murrayc.com> | 2005-12-20 09:17:52 +0000 |
---|---|---|
committer | Murray Cumming <murrayc@murrayc.com> | 2005-12-20 09:17:52 +0000 |
commit | c28ca168dc0de2b53a068e182dbb83463d586262 (patch) | |
tree | 9d888edbb90b14bebd56612184c08b311157fea2 | |
parent | ffb7003199d215e5611c0f14b8f97d4b22205464 (diff) |
2005-12-17 Murray Cumming <murrayc@murrayc.com>
* cairomm/Makefile.am:
* cairomm/refptr.h: Add shared
reference-counting smartpointer, using
the reference-count in the object. A copy
of the tried and tested glibmm RefPtr.
* cairomm/context.cc:
* cairomm/context.h:
* cairomm/fontface.cc:
* cairomm/fontface.h:
* cairomm/pattern.cc:
* cairomm/pattern.h:
* cairomm/surface.cc:
* cairomm/surface.h: Make constructors protected
and add public static create() methods that return
instances in RefPtr<>s. This allows reference-counted
objects to be clearly const or non-const, and allows
casting between related types.
-rw-r--r-- | ChangeLog | 20 | ||||
-rw-r--r-- | cairomm/Makefile.am | 2 | ||||
-rw-r--r-- | cairomm/context.cc | 99 | ||||
-rw-r--r-- | cairomm/context.h | 41 | ||||
-rw-r--r-- | cairomm/fontface.cc | 36 | ||||
-rw-r--r-- | cairomm/fontface.h | 20 | ||||
-rw-r--r-- | cairomm/pattern.cc | 120 | ||||
-rw-r--r-- | cairomm/pattern.h | 108 | ||||
-rw-r--r-- | cairomm/refptr.h | 336 | ||||
-rw-r--r-- | cairomm/surface.cc | 48 | ||||
-rw-r--r-- | cairomm/surface.h | 30 |
11 files changed, 515 insertions, 345 deletions
@@ -1,5 +1,25 @@ 2005-12-17 Murray Cumming <murrayc@murrayc.com> + * cairomm/Makefile.am: + * cairomm/refptr.h: Add shared + reference-counting smartpointer, using + the reference-count in the object. A copy + of the tried and tested glibmm RefPtr. + * cairomm/context.cc: + * cairomm/context.h: + * cairomm/fontface.cc: + * cairomm/fontface.h: + * cairomm/pattern.cc: + * cairomm/pattern.h: + * cairomm/surface.cc: + * cairomm/surface.h: Make constructors protected + and add public static create() methods that return + instances in RefPtr<>s. This allows reference-counted + objects to be clearly const or non-const, and allows + casting between related types. + +2005-12-17 Murray Cumming <murrayc@murrayc.com> + * cairomm/context.cc: * cairomm/context.h: Change set_dash(void) to unset_dash(). Change rotate_deg() to diff --git a/cairomm/Makefile.am b/cairomm/Makefile.am index bee4cd2..f02475a 100644 --- a/cairomm/Makefile.am +++ b/cairomm/Makefile.am @@ -2,7 +2,7 @@ SUBDIRS = INCLUDES = -I$(top_srcdir) @CAIROMM_CFLAGS@ -h_sources_public = cairomm.h context.h enums.h fontface.h fontoptions.h path.h pattern.h surface.h exception.h +h_sources_public = cairomm.h context.h enums.h fontface.h fontoptions.h path.h pattern.h surface.h exception.h refptr.h h_sources_private = private.h cc_sources = context.cc fontface.cc fontoptions.cc path.cc pattern.cc surface.cc exception.cc cc_sources_private = private.cc diff --git a/cairomm/context.cc b/cairomm/context.cc index 3871fe8..bdd2230 100644 --- a/cairomm/context.cc +++ b/cairomm/context.cc @@ -21,13 +21,18 @@ namespace Cairo { -Context::Context(Surface& target) +Context::Context(const RefPtr<Surface>& target) : m_cobject(0) { - m_cobject = cairo_create(target.cobj()); + m_cobject = cairo_create(target->cobj()); check_object_status_and_throw_exception(*this); } +RefPtr<Context> Context::create(const RefPtr<Surface>& target) +{ + return RefPtr<Context>(new Context(target)); +} + Context::Context(cairo_t* cobject, bool has_reference) : m_cobject(0) { @@ -37,15 +42,6 @@ Context::Context(cairo_t* cobject, bool has_reference) m_cobject = cairo_reference(cobject); } -Context::Context(const Context& src) -{ - //Reference-counting, instead of copying by value: - if(!src.m_cobject) - m_cobject = 0; - else - m_cobject = cairo_reference(src.m_cobject); -} - Context::~Context() { if(m_cobject) @@ -53,30 +49,15 @@ Context::~Context() } -Context& Context::operator=(const Context& src) +void Context::reference() const { - //Reference-counting, instead of copying by value: - - if(this == &src) - return *this; - - if(m_cobject == src.m_cobject) - return *this; - - if(m_cobject) - { - cairo_destroy(m_cobject); - m_cobject = 0; - } - - if(!src.m_cobject) - return *this; - - m_cobject = cairo_reference(src.m_cobject); - - return *this; + cairo_reference(m_cobject); } +void Context::unreference() const +{ + cairo_destroy(m_cobject); +} void Context::save() { @@ -96,9 +77,9 @@ void Context::set_operator(Operator op) check_object_status_and_throw_exception(*this); } -void Context::set_source(const Pattern& source) +void Context::set_source(const RefPtr<const Pattern>& source) { - cairo_set_source(m_cobject, const_cast<cairo_pattern_t*>(source.cobj())); + cairo_set_source(m_cobject, const_cast<cairo_pattern_t*>(source->cobj())); check_object_status_and_throw_exception(*this); } @@ -115,9 +96,9 @@ double alpha) check_object_status_and_throw_exception(*this); } -void Context::set_source(Surface& surface, double x, double y) +void Context::set_source(const RefPtr<Surface>& surface, double x, double y) { - cairo_set_source_surface(m_cobject, surface.cobj(), x, y); + cairo_set_source_surface(m_cobject, surface->cobj(), x, y); check_object_status_and_throw_exception(*this); } @@ -319,15 +300,15 @@ void Context::paint_with_alpha(double alpha) check_object_status_and_throw_exception(*this); } -void Context::mask(Pattern& pattern) +void Context::mask(const RefPtr<Pattern>& pattern) { - cairo_mask(m_cobject, pattern.cobj()); + cairo_mask(m_cobject, pattern->cobj()); check_object_status_and_throw_exception(*this); } -void Context::mask(Surface& surface, double surface_x, double surface_y) +void Context::mask(const RefPtr<Surface>& surface, double surface_x, double surface_y) { - cairo_mask_surface(m_cobject, surface.cobj(), surface_x, surface_y); + cairo_mask_surface(m_cobject, surface->cobj(), surface_x, surface_y); check_object_status_and_throw_exception(*this); } @@ -411,7 +392,7 @@ void Context::clip_preserve() check_object_status_and_throw_exception(*this); } -void Context::select_font_face (const std::string& family, FontSlant slant, FontWeight weight) +void Context::select_font_face(const std::string& family, FontSlant slant, FontWeight weight) { cairo_select_font_face (m_cobject, family.c_str(), (cairo_font_slant_t)slant, (cairo_font_weight_t)weight); check_object_status_and_throw_exception(*this); @@ -453,11 +434,18 @@ void Context::show_glyphs(const std::vector<Glyph>& glyphs) check_object_status_and_throw_exception(*this); } -FontFace Context::get_font_face() const +RefPtr<FontFace> Context::get_font_face() +{ + cairo_font_face_t* cfontface = cairo_get_font_face(m_cobject); + check_object_status_and_throw_exception(*this); + return RefPtr<FontFace>(new FontFace(cfontface, false /* does not have reference */)); +} + +RefPtr<const FontFace> Context::get_font_face() const { cairo_font_face_t* cfontface = cairo_get_font_face(m_cobject); check_object_status_and_throw_exception(*this); - return FontFace(cfontface, false /* does not have reference */); + return RefPtr<const FontFace>(new FontFace(cfontface, false /* does not have reference */)); } void Context::get_font_extents(FontExtents& extents) const @@ -466,9 +454,9 @@ void Context::get_font_extents(FontExtents& extents) const check_object_status_and_throw_exception(*this); } -void Context::set_font_face(const FontFace& font_face) +void Context::set_font_face(const RefPtr<const FontFace>& font_face) { - cairo_set_font_face(m_cobject, const_cast<cairo_font_face_t*>(font_face.cobj())); + cairo_set_font_face(m_cobject, const_cast<cairo_font_face_t*>(font_face->cobj())); check_object_status_and_throw_exception(*this); } @@ -503,11 +491,18 @@ Operator Context::get_operator() const return result; } -Pattern Context::get_source() const +RefPtr<Pattern> Context::get_source() { cairo_pattern_t* pattern = cairo_get_source(m_cobject); check_object_status_and_throw_exception(*this); - return Pattern(pattern, false /* does not have reference */); + return RefPtr<Pattern>(new Pattern(pattern, false /* does not have reference */)); +} + +RefPtr<const Pattern> Context::get_source() const +{ + cairo_pattern_t* pattern = cairo_get_source(m_cobject); + check_object_status_and_throw_exception(*this); + return RefPtr<const Pattern>(new Pattern(pattern, false /* does not have reference */)); } double Context::get_tolerance() const @@ -571,18 +566,18 @@ void Context::get_matrix(Matrix& matrix) check_object_status_and_throw_exception(*this); } -Surface Context::get_target() +RefPtr<Surface> Context::get_target() { - cairo_surface_t* surface = cairo_get_target(m_cobject); + cairo_surface_t* surface = cairo_get_target(const_cast<cairo_t*>(m_cobject)); check_object_status_and_throw_exception(*this); - return Surface(surface, false /* does not have reference */); + return RefPtr<Surface>(new Surface(surface, false /* does not have reference */)); } -const Surface Context::get_target() const +RefPtr<const Surface> Context::get_target() const { cairo_surface_t* surface = cairo_get_target(const_cast<cairo_t*>(m_cobject)); check_object_status_and_throw_exception(*this); - return Surface(surface, false /* does not have reference */); + return RefPtr<const Surface>(new Surface(surface, false /* does not have reference */)); } Path* Context::copy_path() const diff --git a/cairomm/context.h b/cairomm/context.h index 4135dea..9aa0cb6 100644 --- a/cairomm/context.h +++ b/cairomm/context.h @@ -53,36 +53,28 @@ typedef cairo_matrix_t Matrix; //A simple struct. //TODO: Derive and add operato */ class Context { +protected: + explicit Context(const RefPtr<Surface>& target); + public: - Context(); - explicit Context(Surface& src); - /** Create a C++ wrapper for the C instance. + /** Create a C++ wrapper for the C instance. This C++ instance should then be given to a RefPtr. * @param cobject The C instance. * @param has_reference Whether we already have a reference. Otherwise, the constructor will take an extra reference. */ explicit Context(cairo_t* cobject, bool has_reference = false); - /** Create a second reference to the context. - * Changing this instance will change the original instance. - */ - Context(const Context& src); + static RefPtr<Context> create(const RefPtr<Surface>& target); - //TODO?: Context(cairo_surface_t *target); virtual ~Context(); - /** Create a second reference to the context. - * Changing this instance will change the original instance. - */ - Context& operator=(const Context& src); - void save(); void restore(); void set_operator(Operator op); - void set_source(const Pattern& source); + void set_source(const RefPtr<const Pattern>& source); void set_source_rgb(double red, double green, double blue); void set_source_rgba(double red, double green, double blue, double alpha); - void set_source(Surface& surface, double x, double y); + void set_source(const RefPtr<Surface>& surface, double x, double y); void set_tolerance(double tolerance); void set_antialias(Antialias antialias); void set_fill_rule(FillRule fill_rule); @@ -116,8 +108,8 @@ public: void close_path(); void paint(); void paint_with_alpha(double alpha); - void mask(Pattern& pattern); - void mask(Surface& surface, double surface_x, double surface_y); + void mask(const RefPtr<Pattern>& pattern); + void mask(const RefPtr<Surface>& surface, double surface_x, double surface_y); void stroke(); void stroke_preserve(); void fill(); @@ -138,15 +130,17 @@ public: void set_font_options(const FontOptions& options); void show_text(const std::string& utf8); void show_glyphs(const std::vector<Glyph>& glyphs); - FontFace get_font_face() const; + RefPtr<FontFace> get_font_face(); + RefPtr<const FontFace> get_font_face() const; void get_font_extents(FontExtents& extents) const; - void set_font_face(const FontFace& font_face); + void set_font_face(const RefPtr<const FontFace>& font_face); void get_text_extents(const std::string& utf8, TextExtents& extents) const; void get_glyph_extents(const std::vector<Glyph>& glyphs, TextExtents& extents) const; void text_path(const std::string& utf8); void glyph_path(const std::vector<Glyph>& glyphs); Operator get_operator() const; - Pattern get_source() const; + RefPtr<Pattern> get_source(); + RefPtr<const Pattern> get_source() const; double get_tolerance() const; Antialias get_antialias() const; void get_current_point (double& x, double& y) const; @@ -158,8 +152,8 @@ public: double get_miter_limit() const; void get_matrix(Matrix& matrix); - Surface get_target(); - const Surface get_target() const; + RefPtr<Surface> get_target(); + RefPtr<const Surface> get_target() const; //TODO: Copy or reference-count a Path somethow instead of asking the caller to delete it? Path* copy_path() const; @@ -177,6 +171,9 @@ public: { return cairo_status(const_cast<cairo_t*>(cobj())); } #endif //DOXYGEN_IGNORE_THIS + void reference() const; + void unreference() const; + protected: diff --git a/cairomm/fontface.cc b/cairomm/fontface.cc index 5580a4d..d77efc9 100644 --- a/cairomm/fontface.cc +++ b/cairomm/fontface.cc @@ -30,44 +30,20 @@ FontFace::FontFace(cairo_font_face_t* cobject, bool has_reference) m_cobject = cairo_font_face_reference(cobject); } -FontFace::FontFace(const FontFace& src) -{ - //Reference-counting, instead of copying by value: - if(!src.m_cobject) - m_cobject = 0; - else - m_cobject = cairo_font_face_reference(src.m_cobject); -} - FontFace::~FontFace() { if(m_cobject) cairo_font_face_destroy(m_cobject); } - -FontFace& FontFace::operator=(const FontFace& src) +void FontFace::reference() const { - //Reference-counting, instead of copying by value: - - if(this == &src) - return *this; - - if(m_cobject == src.m_cobject) - return *this; - - if(m_cobject) - { - cairo_font_face_destroy(m_cobject); - m_cobject = 0; - } - - if(!src.m_cobject) - return *this; - - m_cobject = cairo_font_face_reference(src.m_cobject); + cairo_font_face_reference(m_cobject); +} - return *this; +void FontFace::unreference() const +{ + cairo_font_face_destroy(m_cobject); } /* diff --git a/cairomm/fontface.h b/cairomm/fontface.h index feb152f..97e1985 100644 --- a/cairomm/fontface.h +++ b/cairomm/fontface.h @@ -31,28 +31,21 @@ namespace Cairo */ class FontFace { +protected: + + //TODO?: FontFace(cairo_font_face_t *target); + public: - FontFace(); - /** Create a C++ wrapper for the C instance. + /** Create a C++ wrapper for the C instance. This C++ instance should then be given to a RefPtr. * @param cobject The C instance. * @param has_reference Whether we already have a reference. Otherwise, the constructor will take an extra reference. */ explicit FontFace(cairo_font_face_t* cobject, bool has_reference = false); - /** Create a second reference to the FontFace. - * Changing this instance will change the original instance. - */ - FontFace(const FontFace& src); - //TODO?: FontFace(cairo_font_face_t *target); virtual ~FontFace(); - /** Create a second reference to the FontFace. - * Changing this instance will change the original instance. - */ - FontFace& operator=(const FontFace& src); - /* Don't wrap these until we know what they are good for. void* get_user_data(const cairo_user_data_key_t *key); @@ -70,6 +63,9 @@ public: { return cairo_font_face_status(const_cast<cairo_font_face_t*>(cobj())); } #endif //DOXYGEN_IGNORE_THIS + void reference() const; + void unreference() const; + protected: cobject* m_cobject; diff --git a/cairomm/pattern.cc b/cairomm/pattern.cc index 7be40a5..72978ba 100644 --- a/cairomm/pattern.cc +++ b/cairomm/pattern.cc @@ -35,48 +35,21 @@ Pattern::Pattern(cairo_pattern_t* cobject, bool has_reference) m_cobject = cairo_pattern_reference(cobject); } -Pattern::Pattern(const Pattern& src) -{ - //Reference-counting, instead of copying by value: - if(!src.m_cobject) - m_cobject = 0; - else - m_cobject = cairo_pattern_reference(src.m_cobject); -} - Pattern::~Pattern() { if(m_cobject) cairo_pattern_destroy(m_cobject); } - -Pattern& Pattern::operator=(const Pattern& src) +void Pattern::reference() const { - //Reference-counting, instead of copying by value: - - if(this == &src) - return *this; - - if(m_cobject == src.m_cobject) - return *this; - - if(m_cobject) - { - cairo_pattern_destroy(m_cobject); - m_cobject = 0; - } - - if(!src.m_cobject) - return *this; - - m_cobject = cairo_pattern_reference(src.m_cobject); - - return *this; + cairo_pattern_reference(m_cobject); } - - +void Pattern::unreference() const +{ + cairo_pattern_destroy(m_cobject); +} void Pattern::set_matrix(const cairo_matrix_t &matrix) { @@ -97,42 +70,34 @@ SolidPattern::SolidPattern(cairo_pattern_t* cobject, bool has_reference) { } -SolidPattern::SolidPattern(const SolidPattern& src) -: Pattern(src) -{ -} - SolidPattern::~SolidPattern() { } -SolidPattern SolidPattern::create_rgb(double red, double green, double blue) +RefPtr<SolidPattern> SolidPattern::create_rgb(double red, double green, double blue) { cairo_pattern_t* cobject = cairo_pattern_create_rgb(red, green, blue); check_status_and_throw_exception(cairo_pattern_status(cobject)); - return SolidPattern(cobject, true /* has reference */); + return RefPtr<SolidPattern>(new SolidPattern(cobject, true /* has reference */)); } -SolidPattern SolidPattern::create_rgba(double red, double green, double blue, double alpha) +RefPtr<SolidPattern> SolidPattern::create_rgba(double red, double green, double blue, double alpha) { cairo_pattern_t* cobject = cairo_pattern_create_rgba(red, green, blue, alpha); check_status_and_throw_exception(cairo_pattern_status(cobject)); - return SolidPattern(cobject, true /* has reference */); + return RefPtr<SolidPattern>(new SolidPattern(cobject, true /* has reference */)); } -SolidPattern& SolidPattern::operator=(const SolidPattern& src) +SurfacePattern::SurfacePattern(const RefPtr<Surface>& surface) { - Pattern::operator=(src); - - return *this; + m_cobject = cairo_pattern_create_for_surface(surface->cobj()); + check_object_status_and_throw_exception(*this); } - -SurfacePattern::SurfacePattern(Surface& surface) +RefPtr<SurfacePattern> SurfacePattern::create(const RefPtr<Surface>& surface) { - m_cobject = cairo_pattern_create_for_surface(surface.cobj()); - check_object_status_and_throw_exception(*this); + return RefPtr<SurfacePattern>(new SurfacePattern(surface)); } SurfacePattern::SurfacePattern(cairo_pattern_t* cobject, bool has_reference) @@ -140,23 +105,10 @@ SurfacePattern::SurfacePattern(cairo_pattern_t* cobject, bool has_reference) { } -SurfacePattern::SurfacePattern(const SurfacePattern& src) -: Pattern(src) -{ -} - SurfacePattern::~SurfacePattern() { } - -SurfacePattern& SurfacePattern::operator=(const SurfacePattern& src) -{ - Pattern::operator=(src); - - return *this; -} - void SurfacePattern::set_extend(Extend extend) { cairo_pattern_set_extend(m_cobject, (cairo_extend_t)extend); @@ -194,22 +146,10 @@ Gradient::Gradient(cairo_pattern_t* cobject, bool has_reference) { } -Gradient::Gradient(const Gradient& src) -: Pattern(src) -{ -} - Gradient::~Gradient() { } -Gradient& Gradient::operator=(const Gradient& src) -{ - Pattern::operator=(src); - - return *this; -} - void Gradient::add_color_stop_rgb(double offset, double red, double green, double blue) { cairo_pattern_add_color_stop_rgb(m_cobject, offset, red, green, blue); @@ -230,13 +170,13 @@ LinearGradient::LinearGradient(double x0, double y0, double x1, double y1) check_object_status_and_throw_exception(*this); } -LinearGradient::LinearGradient(cairo_pattern_t* cobject, bool has_reference) -: Gradient(cobject, has_reference) +RefPtr<LinearGradient> LinearGradient::create(double x0, double y0, double x1, double y1) { + return RefPtr<LinearGradient>(new LinearGradient(x0, y0, x1, y1)); } -LinearGradient::LinearGradient(const LinearGradient& src) -: Gradient(src) +LinearGradient::LinearGradient(cairo_pattern_t* cobject, bool has_reference) +: Gradient(cobject, has_reference) { } @@ -245,27 +185,19 @@ LinearGradient::~LinearGradient() } -LinearGradient& LinearGradient::operator=(const LinearGradient& src) -{ - Gradient::operator=(src); - - return *this; -} - - RadialGradient::RadialGradient(double cx0, double cy0, double radius0, double cx1, double cy1, double radius1) { m_cobject = cairo_pattern_create_radial(cx0, cy0, radius0, cx1, cy1, radius1); check_object_status_and_throw_exception(*this); } -RadialGradient::RadialGradient(cairo_pattern_t* cobject, bool has_reference) -: Gradient(cobject, has_reference) +RefPtr<RadialGradient> RadialGradient::create(double cx0, double cy0, double radius0, double cx1, double cy1, double radius1) { + return RefPtr<RadialGradient>(new RadialGradient(cx0, cy0, radius0, cx1, cy1, radius1)); } -RadialGradient::RadialGradient(const RadialGradient& src) -: Gradient(src) +RadialGradient::RadialGradient(cairo_pattern_t* cobject, bool has_reference) +: Gradient(cobject, has_reference) { } @@ -274,12 +206,6 @@ RadialGradient::~RadialGradient() } -RadialGradient& RadialGradient::operator=(const RadialGradient& src) -{ - Gradient::operator=(src); - - return *this; -} diff --git a/cairomm/pattern.h b/cairomm/pattern.h index dd2bb15..6eae3ab 100644 --- a/cairomm/pattern.h +++ b/cairomm/pattern.h @@ -35,28 +35,21 @@ typedef cairo_filter_t Filter; */ class Pattern { -public: +protected: //Use derived constructors. - /** Create a C++ wrapper for the C instance. + //TODO?: Pattern(cairo_pattern_t *target); + +public: + + /** Create a C++ wrapper for the C instance. This C++ instance should then be given to a RefPtr. * @param cobject The C instance. * @param has_reference Whether we already have a reference. Otherwise, the constructor will take an extra reference. */ explicit Pattern(cairo_pattern_t* cobject, bool has_reference = false); - /** Create a second reference to the Pattern. - * Changing this instance will change the original instance. - */ - Pattern(const Pattern& src); - - //TODO?: Pattern(cairo_pattern_t *target); virtual ~Pattern(); - /** Create a second reference to the Pattern. - * Changing this instance will change the original instance. - */ - Pattern& operator=(const Pattern& src); - void set_matrix(const cairo_matrix_t &matrix); void get_matrix(cairo_matrix_t &matrix) const; @@ -70,6 +63,9 @@ public: { return cairo_pattern_status(const_cast<cairo_pattern_t*>(cobj())); } #endif //DOXYGEN_IGNORE_THIS + void reference() const; + void unreference() const; + protected: //Used by derived types only. Pattern(); @@ -79,10 +75,9 @@ protected: class SolidPattern : public Pattern { -public: +protected: - static SolidPattern create_rgb(double red, double green, double blue); - static SolidPattern create_rgba(double red, double green, double blue, double alpha); +public: /** Create a C++ wrapper for the C instance. * @param cobject The C instance. @@ -90,44 +85,33 @@ public: */ explicit SolidPattern(cairo_pattern_t* cobject, bool has_reference = false); - /** Create a second reference to the Pattern. - * Changing this instance will change the original instance. - */ - SolidPattern(const SolidPattern& src); + static RefPtr<SolidPattern> create_rgb(double red, double green, double blue); + static RefPtr<SolidPattern> create_rgba(double red, double green, double blue, double alpha); //TODO?: SolidPattern(cairo_pattern_t *target); virtual ~SolidPattern(); - - /** Create a second reference to the Pattern. - * Changing this instance will change the original instance. - */ - SolidPattern& operator=(const SolidPattern& src); }; class SurfacePattern : public Pattern { -public: +protected: - explicit SurfacePattern(Surface& surface); + explicit SurfacePattern(const RefPtr<Surface>& surface); - /** Create a C++ wrapper for the C instance. + //TODO?: SurfacePattern(cairo_pattern_t *target); + +public: + + /** Create a C++ wrapper for the C instance. This C++ instance should then be given to a RefPtr. * @param cobject The C instance. * @param has_reference Whether we already have a reference. Otherwise, the constructor will take an extra reference. */ explicit SurfacePattern(cairo_pattern_t* cobject, bool has_reference = false); - /** Create a second reference to the Pattern. - * Changing this instance will change the original instance. - */ - SurfacePattern(const SurfacePattern& src); - //TODO?: SurfacePattern(cairo_pattern_t *target); virtual ~SurfacePattern(); - /** Create a second reference to the Pattern. - * Changing this instance will change the original instance. - */ - SurfacePattern& operator=(const SurfacePattern& src); + static RefPtr<SurfacePattern> create(const RefPtr<Surface>& surface); void set_extend(Extend extend); Extend get_extend() const; @@ -137,28 +121,21 @@ public: class Gradient : public Pattern { -public: +protected: //Use derived constructors. - /** Create a C++ wrapper for the C instance. + //TODO?: Gradient(cairo_pattern_t *target); + +public: + + /** Create a C++ wrapper for the C instance. This C++ instance should then be given to a RefPtr. * @param cobject The C instance. * @param has_reference Whether we already have a reference. Otherwise, the constructor will take an extra reference. */ explicit Gradient(cairo_pattern_t* cobject, bool has_reference = false); - /** Create a second reference to the Pattern. - * Changing this instance will change the original instance. - */ - Gradient(const Gradient& src); - - //TODO?: Gradient(cairo_pattern_t *target); virtual ~Gradient(); - /** Create a second reference to the Pattern. - * Changing this instance will change the original instance. - */ - Gradient& operator=(const Gradient& src); - void add_color_stop_rgb(double offset, double red, double green, double blue); void add_color_stop_rgba(double offset, double red, double green, double blue, double alpha); @@ -168,54 +145,43 @@ protected: class LinearGradient : public Gradient { -public: +protected: LinearGradient(double x0, double y0, double x1, double y1); - /** Create a C++ wrapper for the C instance. +public: + + /** Create a C++ wrapper for the C instance. This C++ instance should then be given to a RefPtr. * @param cobject The C instance. * @param has_reference Whether we already have a reference. Otherwise, the constructor will take an extra reference. */ explicit LinearGradient(cairo_pattern_t* cobject, bool has_reference = false); - /** Create a second reference to the Pattern. - * Changing this instance will change the original instance. - */ - LinearGradient(const LinearGradient& src); - //TODO?: LinearGradient(cairo_pattern_t *target); virtual ~LinearGradient(); - /** Create a second reference to the Pattern. - * Changing this instance will change the original instance. - */ - LinearGradient& operator=(const LinearGradient& src); + static RefPtr<LinearGradient> create(double x0, double y0, double x1, double y1); }; class RadialGradient : public Gradient { -public: +protected: RadialGradient(double cx0, double cy0, double radius0, double cx1, double cy1, double radius1); - /** Create a C++ wrapper for the C instance. +public: + + /** Create a C++ wrapper for the C instance. This C++ instance should then be given to a RefPtr. * @param cobject The C instance. * @param has_reference Whether we already have a reference. Otherwise, the constructor will take an extra reference. */ explicit RadialGradient(cairo_pattern_t* cobject, bool has_reference = false); - /** Create a second reference to the Pattern. - * Changing this instance will change the original instance. - */ - RadialGradient(const RadialGradient& src); //TODO?: RadialGradient(cairo_pattern_t *target); virtual ~RadialGradient(); - /** Create a second reference to the Pattern. - * Changing this instance will change the original instance. - */ - RadialGradient& operator=(const RadialGradient& src); + static RefPtr<RadialGradient> create(double cx0, double cy0, double radius0, double cx1, double cy1, double radius1); }; } // namespace Cairo diff --git a/cairomm/refptr.h b/cairomm/refptr.h new file mode 100644 index 0000000..70b9436 --- /dev/null +++ b/cairomm/refptr.h @@ -0,0 +1,336 @@ +// -*- c++ -*- +#ifndef _cairo_REFPTR_H +#define _cairo_REFPTR_H + +/* $Id: refptr.h,v 1.1 2005-12-20 09:17:53 murrayc Exp $ */ + +/* Copyright 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +namespace Cairo +{ + +/** RefPtr<> is a reference-counting shared smartpointer. + * + * Some objects in gtkmm are obtained from a shared + * store. Consequently you cannot instantiate them yourself. Instead they + * return a RefPtr which behaves much like an ordinary pointer in that members + * can be reached with the usual <code>object_ptr->member</code> notation. + * Unlike most other smart pointers, RefPtr doesn't support dereferencing + * through <code>*object_ptr</code>. + * + * Reference counting means that a shared reference count is incremented each + * time a RefPtr is copied, and decremented each time a RefPtr is destroyed, + * for instance when it leaves its scope. When the reference count reaches + * zero, the contained object is deleted, meaning you don't need to remember + * to delete the object. + * + * RefPtr<> can store any class that has reference() and unreference() methods. + */ +template <class T_CppObject> +class RefPtr +{ +public: + /** Default constructor + * + * Afterwards it will be null and use of -> will cause a segmentation fault. + */ + inline RefPtr(); + + /// Destructor - decrements reference count. + inline ~RefPtr(); + + /// For use only by the ::create() methods. + explicit inline RefPtr(T_CppObject* pCppObject); + + /** Copy constructor + * + * This increments the shared reference count. + */ + inline RefPtr(const RefPtr<T_CppObject>& src); + + /** Copy constructor (from different, but castable type). + * + * Increments the reference count. + */ + template <class T_CastFrom> + inline RefPtr(const RefPtr<T_CastFrom>& src); + + /** Swap the contents of two RefPtr<>. + * This method swaps the internal pointers to T_CppObject. This can be + * done safely without involving a reference/unreference cycle and is + * therefore highly efficient. + */ + inline void swap(RefPtr<T_CppObject>& other); + + /// Copy from another RefPtr: + inline RefPtr<T_CppObject>& operator=(const RefPtr<T_CppObject>& src); + + /** Copy from different, but castable type). + * + * Increments the reference count. + */ + template <class T_CastFrom> + inline RefPtr<T_CppObject>& operator=(const RefPtr<T_CastFrom>& src); + + /// Tests whether the RefPtr<> point to the same underlying instance. + inline bool operator==(const RefPtr<T_CppObject>& src) const; + + /// See operator==(). + inline bool operator!=(const RefPtr<T_CppObject>& src) const; + + /** Dereferencing. + * + * Use the methods of the underlying instance like so: + * <code>refptr->memberfun()</code>. + */ + inline T_CppObject* operator->() const; + + /** Test whether the RefPtr<> points to any underlying instance. + * + * Mimics usage of ordinary pointers: + * @code + * if (ptr) + * do_something(); + * @endcode + */ + inline operator bool() const; + + /// Set underlying instance to 0, decrementing reference count of existing instance appropriately. + inline void clear(); + + + /** Dynamic cast to derived class. + * + * The RefPtr can't be cast with the usual notation so instead you can use + * @code + * ptr_derived = RefPtr<Derived>::cast_dynamic(ptr_base); + * @endcode + */ + template <class T_CastFrom> + static inline RefPtr<T_CppObject> cast_dynamic(const RefPtr<T_CastFrom>& src); + + /** Static cast to derived class. + * + * Like the dynamic cast; the notation is + * @code + * ptr_derived = RefPtr<Derived>::cast_static(ptr_base); + * @endcode + */ + template <class T_CastFrom> + static inline RefPtr<T_CppObject> cast_static(const RefPtr<T_CastFrom>& src); + + /** Cast to non-const. + * + * The RefPtr can't be cast with the usual notation so instead you can use + * @code + * ptr_unconst = RefPtr<UnConstType>::cast_const(ptr_const); + * @endcode + */ + template <class T_CastFrom> + static inline RefPtr<T_CppObject> cast_const(const RefPtr<T_CastFrom>& src); + +private: + T_CppObject* pCppObject_; +}; + + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +// RefPtr<>::operator->() comes first here since it's used by other methods. +// If it would come after them it wouldn't be inlined. + +template <class T_CppObject> inline +T_CppObject* RefPtr<T_CppObject>::operator->() const +{ + return pCppObject_; +} + +template <class T_CppObject> inline +RefPtr<T_CppObject>::RefPtr() +: + pCppObject_ (0) +{} + +template <class T_CppObject> inline +RefPtr<T_CppObject>::~RefPtr() +{ + if(pCppObject_) + pCppObject_->unreference(); // This could cause pCppObject to be deleted. +} + +template <class T_CppObject> inline +RefPtr<T_CppObject>::RefPtr(T_CppObject* pCppObject) +: + pCppObject_ (pCppObject) +{} + +template <class T_CppObject> inline +RefPtr<T_CppObject>::RefPtr(const RefPtr<T_CppObject>& src) +: + pCppObject_ (src.pCppObject_) +{ + if(pCppObject_) + pCppObject_->reference(); +} + +// The templated ctor allows copy construction from any object that's +// castable. Thus, it does downcasts: +// base_ref = derived_ref +template <class T_CppObject> + template <class T_CastFrom> +inline +RefPtr<T_CppObject>::RefPtr(const RefPtr<T_CastFrom>& src) +: + // A different RefPtr<> will not allow us access to pCppObject_. We need + // to add a get_underlying() for this, but that would encourage incorrect + // use, so we use the less well-known operator->() accessor: + pCppObject_ (src.operator->()) +{ + if(pCppObject_) + pCppObject_->reference(); +} + +template <class T_CppObject> inline +void RefPtr<T_CppObject>::swap(RefPtr<T_CppObject>& other) +{ + T_CppObject *const temp = pCppObject_; + pCppObject_ = other.pCppObject_; + other.pCppObject_ = temp; +} + +template <class T_CppObject> inline +RefPtr<T_CppObject>& RefPtr<T_CppObject>::operator=(const RefPtr<T_CppObject>& src) +{ + // In case you haven't seen the swap() technique to implement copy + // assignment before, here's what it does: + // + // 1) Create a temporary RefPtr<> instance via the copy ctor, thereby + // increasing the reference count of the source object. + // + // 2) Swap the internal object pointers of *this and the temporary + // RefPtr<>. After this step, *this already contains the new pointer, + // and the old pointer is now managed by temp. + // + // 3) The destructor of temp is executed, thereby unreferencing the + // old object pointer. + // + // This technique is described in Herb Sutter's "Exceptional C++", and + // has a number of advantages over conventional approaches: + // + // - Code reuse by calling the copy ctor. + // - Strong exception safety for free. + // - Self assignment is handled implicitely. + // - Simplicity. + // - It just works and is hard to get wrong; i.e. you can use it without + // even thinking about it to implement copy assignment whereever the + // object data is managed indirectly via a pointer, which is very common. + + RefPtr<T_CppObject> temp (src); + this->swap(temp); + return *this; +} + +template <class T_CppObject> + template <class T_CastFrom> +inline +RefPtr<T_CppObject>& RefPtr<T_CppObject>::operator=(const RefPtr<T_CastFrom>& src) +{ + RefPtr<T_CppObject> temp (src); + this->swap(temp); + return *this; +} + +template <class T_CppObject> inline +bool RefPtr<T_CppObject>::operator==(const RefPtr<T_CppObject>& src) const +{ + return (pCppObject_ == src.pCppObject_); +} + +template <class T_CppObject> inline +bool RefPtr<T_CppObject>::operator!=(const RefPtr<T_CppObject>& src) const +{ + return (pCppObject_ != src.pCppObject_); +} + +template <class T_CppObject> inline +RefPtr<T_CppObject>::operator bool() const +{ + return (pCppObject_ != 0); +} + +template <class T_CppObject> inline +void RefPtr<T_CppObject>::clear() +{ + RefPtr<T_CppObject> temp; // swap with an empty RefPtr<> to clear *this + this->swap(temp); +} + +template <class T_CppObject> + template <class T_CastFrom> +inline +RefPtr<T_CppObject> RefPtr<T_CppObject>::cast_dynamic(const RefPtr<T_CastFrom>& src) +{ + T_CppObject *const pCppObject = dynamic_cast<T_CppObject*>(src.operator->()); + + if(pCppObject) + pCppObject->reference(); + + return RefPtr<T_CppObject>(pCppObject); +} + +template <class T_CppObject> + template <class T_CastFrom> +inline +RefPtr<T_CppObject> RefPtr<T_CppObject>::cast_static(const RefPtr<T_CastFrom>& src) +{ + T_CppObject *const pCppObject = static_cast<T_CppObject*>(src.operator->()); + + if(pCppObject) + pCppObject->reference(); + + return RefPtr<T_CppObject>(pCppObject); +} + +template <class T_CppObject> + template <class T_CastFrom> +inline +RefPtr<T_CppObject> RefPtr<T_CppObject>::cast_const(const RefPtr<T_CastFrom>& src) +{ + T_CppObject *const pCppObject = const_cast<T_CppObject*>(src.operator->()); + + if(pCppObject) + pCppObject->reference(); + + return RefPtr<T_CppObject>(pCppObject); +} + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ + +/** @relates Glib::RefPtr */ +template <class T_CppObject> inline +void swap(RefPtr<T_CppObject>& lhs, RefPtr<T_CppObject>& rhs) +{ + lhs.swap(rhs); +} + +} // namespace Cairo + + +#endif /* _cairo_REFPTR_H */ + diff --git a/cairomm/surface.cc b/cairomm/surface.cc index e2194b0..4c32528 100644 --- a/cairomm/surface.cc +++ b/cairomm/surface.cc @@ -21,7 +21,7 @@ namespace Cairo { -Surface::Surface(cairo_surface_t* cobject, bool has_reference) +Surface::Surface(cairo_surface_t* cobject, bool has_reference) : m_cobject(0) { if(has_reference) @@ -30,65 +30,31 @@ Surface::Surface(cairo_surface_t* cobject, bool has_reference) m_cobject = cairo_surface_reference(cobject); } -Surface::Surface(const Surface& src) -{ - //Reference-counting, instead of copying by value: - if(!src.m_cobject) - m_cobject = 0; - else - m_cobject = cairo_surface_reference(src.m_cobject); -} - Surface::~Surface() { if(m_cobject) cairo_surface_destroy(m_cobject); } - -Surface& Surface::operator=(const Surface& src) -{ - //Reference-counting, instead of copying by value: - - if(this == &src) - return *this; - - if(m_cobject == src.m_cobject) - return *this; - - if(m_cobject) - { - cairo_surface_destroy(m_cobject); - m_cobject = 0; - } - - if(!src.m_cobject) - return *this; - - m_cobject = cairo_surface_reference(src.m_cobject); - - return *this; -} - -Surface Surface::create(Format format, int width, int height) +RefPtr<Surface> Surface::create(Format format, int width, int height) { cairo_surface_t* cobject = cairo_image_surface_create((cairo_format_t)format, width, height); check_status_and_throw_exception(cairo_surface_status(cobject)); - return Surface(cobject, true /* has reference */); + return RefPtr<Surface>(new Surface(cobject, true /* has reference */)); } -Surface Surface::create(unsigned char* data, Format format, int width, int height, int stride) +RefPtr<Surface> Surface::create(unsigned char* data, Format format, int width, int height, int stride) { cairo_surface_t* cobject = cairo_image_surface_create_for_data(data, (cairo_format_t)format, width, height, stride); check_status_and_throw_exception(cairo_surface_status(cobject)); - return Surface(cobject, true /* has reference */); + return RefPtr<Surface>(new Surface(cobject, true /* has reference */)); } -Surface Surface::create(const Surface& other, Content content, int width, int height) +RefPtr<Surface> Surface::create(const Surface& other, Content content, int width, int height) { cairo_surface_t* cobject = cairo_surface_create_similar(other.m_cobject, (cairo_content_t)content, width, height); check_status_and_throw_exception(cairo_surface_status(cobject)); - return Surface(cobject, true /* has reference */); + return RefPtr<Surface>(new Surface(cobject, true /* has reference */)); } void Surface::finish() diff --git a/cairomm/surface.h b/cairomm/surface.h index 59d1489..e63bfdb 100644 --- a/cairomm/surface.h +++ b/cairomm/surface.h @@ -20,6 +20,7 @@ #include <cairomm/fontoptions.h> #include <cairomm/enums.h> +#include <cairomm/refptr.h> #include <cairo/cairo.h> @@ -37,34 +38,22 @@ typedef cairo_format_t Format; */ class Surface { +protected: + //TODO?: Surface(cairo_surface_t *target); + public: - Surface(); - /** Create a C++ wrapper for the C instance. + /** Create a C++ wrapper for the C instance. This C++ instance should then be given to a RefPtr. * @param cobject The C instance. * @param has_reference Whether we already have a reference. Otherwise, the constructor will take an extra reference. */ explicit Surface(cairo_surface_t* cobject, bool has_reference = false); - /** Create a second reference to the surface. - * Changing this instance will change the original instance. - */ - Surface(const Surface& src); - - //TODO?: Surface(cairo_surface_t *target); virtual ~Surface(); - /** Create a second reference to the surface. - * Changing this instance will change the original instance. - */ - Surface& operator=(const Surface& src); - - //We use create_*() methods, instead of constructors, because - //a) We want to make it clear that these are new instance, not just new references to the same instances. - //b) Overloading on parameter types are not always enough to distinguish them. - static Surface create(const Surface& other, Content content, int width, int height); - static Surface create(Format format, int width, int height); - static Surface create(unsigned char* data, Format format, int width, int height, int stride); + static RefPtr<Surface> create(const Surface& other, Content content, int width, int height); + static RefPtr<Surface> create(Format format, int width, int height); + static RefPtr<Surface> create(unsigned char* data, Format format, int width, int height, int stride); //void write_to_png(const std::string& filename); //void write_to_png_stream(cairo_write_func_t write_func, void *closure); //TODO: Use a sigc::slot? @@ -98,6 +87,9 @@ public: { return cairo_surface_status(const_cast<cairo_surface_t*>(cobj())); } #endif //DOXYGEN_IGNORE_THIS + void reference() const; + void unreference() const; + protected: cobject* m_cobject; }; |