summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMurray Cumming <murrayc@murrayc.com>2005-12-20 09:17:52 +0000
committerMurray Cumming <murrayc@murrayc.com>2005-12-20 09:17:52 +0000
commitc28ca168dc0de2b53a068e182dbb83463d586262 (patch)
tree9d888edbb90b14bebd56612184c08b311157fea2
parentffb7003199d215e5611c0f14b8f97d4b22205464 (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--ChangeLog20
-rw-r--r--cairomm/Makefile.am2
-rw-r--r--cairomm/context.cc99
-rw-r--r--cairomm/context.h41
-rw-r--r--cairomm/fontface.cc36
-rw-r--r--cairomm/fontface.h20
-rw-r--r--cairomm/pattern.cc120
-rw-r--r--cairomm/pattern.h108
-rw-r--r--cairomm/refptr.h336
-rw-r--r--cairomm/surface.cc48
-rw-r--r--cairomm/surface.h30
11 files changed, 515 insertions, 345 deletions
diff --git a/ChangeLog b/ChangeLog
index d39bc8e..3590fe0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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;
};