From 11d9ea1f2c58e2b9ef0b0a12695e2de8ffce4429 Mon Sep 17 00:00:00 2001 From: "pavlov%pavlov.net" Date: Thu, 30 Jun 2005 04:58:27 +0000 Subject: [PATCH] Adding more utility functions to thebes from vlad. Cleaning up some coding style inconsistencies. --- gfx/thebes/public/Makefile.in | 4 ++ gfx/thebes/public/gfxASurface.h | 25 +++++-- gfx/thebes/public/gfxContext.h | 27 +++++--- gfx/thebes/public/gfxImageSurface.h | 16 +++-- gfx/thebes/public/gfxMatrix.h | 16 ++++- gfx/thebes/public/gfxPattern.h | 4 +- gfx/thebes/public/gfxPoint.h | 6 ++ gfx/thebes/public/gfxTypes.h | 11 +++- gfx/thebes/public/gfxWindowsSurface.h | 1 - gfx/thebes/public/gfxXlibSurface.h | 30 ++++++++- gfx/thebes/src/Makefile.in | 10 ++- gfx/thebes/src/gfxContext.cpp | 95 +++++++++++++++++++++++---- gfx/thebes/src/gfxImageSurface.cpp | 45 +++++++++++-- gfx/thebes/src/gfxXlibSurface.cpp | 47 ++++++++++++- 14 files changed, 289 insertions(+), 48 deletions(-) diff --git a/gfx/thebes/public/Makefile.in b/gfx/thebes/public/Makefile.in index ca5a3abee380..f70bba8f8274 100644 --- a/gfx/thebes/public/Makefile.in +++ b/gfx/thebes/public/Makefile.in @@ -26,4 +26,8 @@ ifeq ($(MOZ_GFX_TOOLKIT),windows) EXPORTS += gfxWindowsSurface.h endif +ifeq ($(MOZ_GFX_TOOLKIT),gtk2) +EXPORTS += gfxXlibSurface.h +endif + include $(topsrcdir)/config/rules.mk diff --git a/gfx/thebes/public/gfxASurface.h b/gfx/thebes/public/gfxASurface.h index cc6cb263caba..15dfddcf31e2 100644 --- a/gfx/thebes/public/gfxASurface.h +++ b/gfx/thebes/public/gfxASurface.h @@ -43,22 +43,37 @@ #include "gfxTypes.h" class gfxASurface { - THEBES_DECL_REFCOUNTING + THEBES_DECL_REFCOUNTING_ABSTRACT public: /*** this DOES NOT addref the surface */ - cairo_surface_t *CairoSurface() { return mSurface; } + cairo_surface_t* CairoSurface() { return mSurface; } protected: - void Init(cairo_surface_t* surface) { + void Init(cairo_surface_t *surface) { + mDestroyed = PR_FALSE; mSurface = surface; } - virtual ~gfxASurface() { + void Destroy() { + if (mDestroyed) { + NS_WARNING("Calling Destroy on an already-destroyed surface!"); + return; + } + cairo_surface_destroy(mSurface); + mDestroyed = PR_TRUE; } - cairo_surface_t* mSurface; + virtual ~gfxASurface() { + if (!mDestroyed) { + NS_WARNING("gfxASurface::~gfxASurface called, but cairo surface was not destroyed! (Did someone forget to call Destroy()?)"); + } + } + +protected: + cairo_surface_t *mSurface; + PRBool mDestroyed; }; #endif /* GFX_ASURFACE_H */ diff --git a/gfx/thebes/public/gfxContext.h b/gfx/thebes/public/gfxContext.h index 61f08200c8bc..a131036eaa76 100644 --- a/gfx/thebes/public/gfxContext.h +++ b/gfx/thebes/public/gfxContext.h @@ -46,22 +46,23 @@ #include "gfxPoint.h" #include "gfxRect.h" #include "gfxTypes.h" +#include "gfxMatrix.h" +#include "gfxPattern.h" -class gfxMatrix; class gfxRegion; class gfxFilter; class gfxTextRun; -class gfxPattern; class gfxContext { THEBES_DECL_REFCOUNTING public: - gfxContext(gfxASurface* surface); + gfxContext(gfxASurface *surface); ~gfxContext(); // this does not addref gfxASurface* CurrentSurface(); + cairo_t* GetCairo() { return mCairo; } /** ** State @@ -93,8 +94,10 @@ public: void NegativeArc(gfxPoint center, gfxFloat radius, gfxFloat angle1, gfxFloat angle2); + // path helpers + void Line(gfxPoint start, gfxPoint end); // XXX snapToPixels option? void Rectangle(gfxRect rect, PRBool snapToPixels = PR_FALSE); - + void Ellipse(gfxPoint center, gfxSize dimensions); void Polygon(const gfxPoint *points, PRUint32 numPoints); /** @@ -119,6 +122,7 @@ public: void Multiply(const gfxMatrix& other); void SetMatrix(const gfxMatrix& matrix); + void IdentityMatrix(); gfxMatrix CurrentMatrix() const; gfxPoint DeviceToUser(gfxPoint point) const; @@ -131,8 +135,8 @@ public: **/ void SetColor(const gfxRGBA& c); - void SetPattern(gfxPattern* pattern); - void SetSource(gfxASurface* surface) { + void SetPattern(gfxPattern *pattern); + void SetSource(gfxASurface *surface) { SetSource(surface, gfxPoint(0, 0)); } void SetSource(gfxASurface* surface, gfxPoint origin); @@ -148,13 +152,20 @@ public: // Creates a new path with a rectangle from 0,0 to size.w,size.h // and calls cairo_fill - void DrawSurface(gfxASurface* surface, gfxSize size); + void DrawSurface(gfxASurface *surface, gfxSize size); /** ** Line Properties **/ - void SetDash(gfxFloat* dashes, int ndash, gfxFloat offset); + typedef enum { + gfxLineSolid, + gfxLineDashed, + gfxLineDotted + } gfxLineType; + + void SetDash(gfxLineType ltype); + void SetDash(gfxFloat *dashes, int ndash, gfxFloat offset); //void getDash() const; void SetLineWidth(gfxFloat width); diff --git a/gfx/thebes/public/gfxImageSurface.h b/gfx/thebes/public/gfxImageSurface.h index 849791dfe28c..48ef7448c55e 100644 --- a/gfx/thebes/public/gfxImageSurface.h +++ b/gfx/thebes/public/gfxImageSurface.h @@ -47,17 +47,25 @@ class gfxImageSurface : public gfxASurface { THEBES_DECL_ISUPPORTS_INHERITED public: - gfxImageSurface(int format, long width, long height); + typedef enum { + ImageFormatARGB32, + ImageFormatRGB24, + ImageFormatA8, + ImageFormatA1 + } gfxImageFormat; + + gfxImageSurface(gfxImageFormat format, long width, long height); virtual ~gfxImageSurface(); // ImageSurface methods - int Format() const { return 0; } + int Format() const { return mFormat; } long Width() const { return mWidth; } long Height() const { return mHeight; } - unsigned char* GetData() { return mData; } // delete this data under us and die. + long Stride() const; + unsigned char* Data() { return mData; } // delete this data under us and die. private: - unsigned char* mData; + unsigned char *mData; int mFormat; long mWidth; long mHeight; diff --git a/gfx/thebes/public/gfxMatrix.h b/gfx/thebes/public/gfxMatrix.h index e6a30d44e8d2..3d82f26d2ad1 100644 --- a/gfx/thebes/public/gfxMatrix.h +++ b/gfx/thebes/public/gfxMatrix.h @@ -38,10 +38,9 @@ #ifndef GFX_MATRIX_H #define GFX_MATRIX_H -#include - #include +#include "gfxPoint.h" #include "gfxTypes.h" // XX - I don't think this class should use gfxFloat at all, @@ -89,6 +88,7 @@ public: *xx = mat.xx; *yx = mat.yx; *xy = mat.xy; + *yy = mat.yy; *x0 = mat.x0; *y0 = mat.y0; } @@ -135,6 +135,18 @@ public: void TransformPoint(gfxFloat *x, gfxFloat *y) const { cairo_matrix_transform_point(&mat, x, y); } + + gfxSize GetScale() const { + return gfxSize(mat.xx, mat.yy); + } + + gfxPoint GetTranslate() const { + return gfxPoint(mat.x0, mat.y0); + } + + bool HasShear() const { + return ((mat.xy != 0.0) || (mat.yx != 0.0)); + } }; #endif /* GFX_MATRIX_H */ diff --git a/gfx/thebes/public/gfxPattern.h b/gfx/thebes/public/gfxPattern.h index a88aec6b430d..d05491c6f90f 100644 --- a/gfx/thebes/public/gfxPattern.h +++ b/gfx/thebes/public/gfxPattern.h @@ -46,6 +46,8 @@ #include "gfxTypes.h" class gfxPattern { + THEBES_DECL_REFCOUNTING + public: // from another surface gfxPattern(gfxASurface* surface) { @@ -64,7 +66,7 @@ public: cx1, cy1, radius1); } - ~gfxPattern() { + virtual ~gfxPattern() { cairo_pattern_destroy(mPattern); } diff --git a/gfx/thebes/public/gfxPoint.h b/gfx/thebes/public/gfxPoint.h index 26ccbd45f134..aceef7963343 100644 --- a/gfx/thebes/public/gfxPoint.h +++ b/gfx/thebes/public/gfxPoint.h @@ -83,6 +83,12 @@ struct gfxPoint { gfxPoint operator+(const gfxSize& s) const { return gfxPoint(x + s.width, y + s.height); } + gfxPoint operator-(const gfxPoint& p) const { + return gfxPoint(x - p.x, y - p.y); + } + gfxPoint operator-(const gfxSize& s) const { + return gfxPoint(x - s.width, y - s.height); + } gfxPoint& round() { x = ::floor(x + 0.5); y = ::floor(y + 0.5); diff --git a/gfx/thebes/public/gfxTypes.h b/gfx/thebes/public/gfxTypes.h index e0e9e6e7ddaa..b1be89f0ee08 100644 --- a/gfx/thebes/public/gfxTypes.h +++ b/gfx/thebes/public/gfxTypes.h @@ -55,9 +55,18 @@ typedef double gfxFloat; #include "nsAutoPtr.h" #define THEBES_IMPL_REFCOUNTING(_class) \ - NS_IMPL_ADDREF(_class) \ + NS_IMPL_ADDREF(_class) \ NS_IMPL_RELEASE(_class) +#define THEBES_DECL_REFCOUNTING_ABSTRACT \ +public: \ + NS_IMETHOD_(nsrefcnt) AddRef(void) = 0; \ + NS_IMETHOD_(nsrefcnt) Release(void) = 0; \ +protected: \ + nsAutoRefCnt mRefCnt; \ + NS_DECL_OWNINGTHREAD \ +public: + #define THEBES_DECL_REFCOUNTING \ public: \ diff --git a/gfx/thebes/public/gfxWindowsSurface.h b/gfx/thebes/public/gfxWindowsSurface.h index ec003945c736..0e110fff5133 100644 --- a/gfx/thebes/public/gfxWindowsSurface.h +++ b/gfx/thebes/public/gfxWindowsSurface.h @@ -39,7 +39,6 @@ #define GFX_WINDOWSSURFACE_H #include "gfxASurface.h" -#include "gfxPoint.h" #include diff --git a/gfx/thebes/public/gfxXlibSurface.h b/gfx/thebes/public/gfxXlibSurface.h index 8c5d14109f71..a7ab5f7b1230 100644 --- a/gfx/thebes/public/gfxXlibSurface.h +++ b/gfx/thebes/public/gfxXlibSurface.h @@ -46,9 +46,35 @@ class gfxXlibSurface : public gfxASurface { THEBES_DECL_ISUPPORTS_INHERITED public: - gfxXlibSurface(Display *dpy, Drawable drawable, - Visual *visual); + // create a surface for the specified dpy/drawable/visual. + // Will use XGetGeometry to query the window/pixmap size. + gfxXlibSurface(Display *dpy, Drawable drawable, Visual *visual); + + // create a surface for the specified dpy/drawable/visual, + // with explicitly provided width/height. + gfxXlibSurface(Display *dpy, Drawable drawable, Visual *visual, unsigned long width, unsigned long height); + + // create a new Pixmap on the display dpy, with + // the root window as the parent and the default depth + // for the default screen, and attach the given visual + gfxXlibSurface(Display *dpy, Visual *visual, unsigned long width, unsigned long height); + virtual ~gfxXlibSurface(); + + unsigned long Width() { return mWidth; } + unsigned long Height() { return mHeight; } + + Display* XDisplay() { return mDisplay; } + Drawable XDrawable() { return mDrawable; } + +protected: + PRBool mOwnsPixmap; + + Display *mDisplay; + Drawable mDrawable; + + unsigned long mWidth; + unsigned long mHeight; }; #endif /* GFX_XLIBSURFACE_H */ diff --git a/gfx/thebes/src/Makefile.in b/gfx/thebes/src/Makefile.in index c918ca390ad3..072b6a217cd3 100644 --- a/gfx/thebes/src/Makefile.in +++ b/gfx/thebes/src/Makefile.in @@ -7,7 +7,7 @@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk MODULE = thebes -LIBRARY_NAME = libthebes +LIBRARY_NAME = thebes LIBXUL_LIBRARY = 1 REQUIRES = \ @@ -18,13 +18,19 @@ REQUIRES = \ CPPSRCS = \ gfxContext.cpp \ - gfxImageSurface.cpp + gfxImageSurface.cpp \ + gfxPattern.cpp \ + $(NULL) ifeq ($(MOZ_GFX_TOOLKIT),windows) CPPSRCS += gfxWindowsSurface.cpp endif +ifeq ($(MOZ_GFX_TOOLKIT),gtk2) +CPPSRCS += gfxXlibSurface.cpp +endif + FORCE_STATIC_LIB = 1 # This library is used by other shared libs in a static build FORCE_USE_PIC = 1 diff --git a/gfx/thebes/src/gfxContext.cpp b/gfx/thebes/src/gfxContext.cpp index 949bef87aeeb..082a4f0975d6 100644 --- a/gfx/thebes/src/gfxContext.cpp +++ b/gfx/thebes/src/gfxContext.cpp @@ -35,6 +35,11 @@ * * ***** END LICENSE BLOCK ***** */ +#ifdef _MSC_VER +#define _USE_MATH_DEFINES +#endif +#include + #include "gfxContext.h" #include "gfxColor.h" @@ -42,19 +47,20 @@ #include "gfxASurface.h" #include "gfxPattern.h" + THEBES_IMPL_REFCOUNTING(gfxContext) -gfxContext::gfxContext(gfxASurface* surface) +gfxContext::gfxContext(gfxASurface *surface) : + mSurface(surface) { mCairo = cairo_create(surface->CairoSurface()); - mSurface = surface; } gfxContext::~gfxContext() { cairo_destroy(mCairo); } -gfxASurface* gfxContext::CurrentSurface() +gfxASurface *gfxContext::CurrentSurface() { return mSurface; } @@ -108,14 +114,20 @@ void gfxContext::Arc(gfxPoint center, gfxFloat radius, cairo_arc(mCairo, center.x, center.y, radius, angle1, angle2); } +void gfxContext::Line(gfxPoint start, gfxPoint end) +{ + MoveTo(start); + LineTo(end); +} + void gfxContext::Rectangle(gfxRect rect, PRBool snapToPixels) { if (snapToPixels) { - gfxPoint p1 = UserToDevice (rect.pos); - gfxPoint p2 = UserToDevice (rect.pos + rect.size); + gfxPoint p1 = UserToDevice(rect.pos); + gfxPoint p2 = UserToDevice(rect.pos + rect.size); - gfxPoint p3 = UserToDevice (rect.pos + gfxSize(rect.size.width, 0.0)); - gfxPoint p4 = UserToDevice (rect.pos + gfxSize(0.0, rect.size.height)); + gfxPoint p3 = UserToDevice(rect.pos + gfxSize(rect.size.width, 0.0)); + gfxPoint p4 = UserToDevice(rect.pos + gfxSize(0.0, rect.size.height)); if (p1.x != p4.x || p2.x != p3.x || @@ -145,14 +157,49 @@ dontsnap: cairo_rectangle(mCairo, rect.pos.x, rect.pos.y, rect.size.width, rect.size.height); } +void gfxContext::Ellipse(gfxPoint center, gfxSize dimensions) +{ + // circle? + if (dimensions.width == dimensions.height) { + double radius = dimensions.width / 2.0; + + cairo_arc(mCairo, center.x, center.y, radius, 0, 2.0 * M_PI); + } else { + double x = center.x; + double y = center.y; + double w = dimensions.width; + double h = dimensions.height; + + cairo_new_path(mCairo); + cairo_move_to(mCairo, x + w/2.0, y); + + cairo_rel_curve_to(mCairo, + 0, 0, + w / 2.0, 0, + w / 2.0, h / 2.0); + cairo_rel_curve_to(mCairo, + 0, 0, + 0, h / 2.0, + - w / 2.0, h / 2.0); + cairo_rel_curve_to(mCairo, + 0, 0, + - w / 2.0, 0, + - w / 2.0, - h / 2.0); + cairo_rel_curve_to(mCairo, + 0, 0, + 0, - h / 2.0, + w / 2.0, - h / 2.0); + } +} + void gfxContext::Polygon(const gfxPoint *points, PRUint32 numPoints) { if (numPoints == 0) return; - cairo_move_to(mCairo, (gfxFloat)points[0].x, (gfxFloat)points[0].y); - for (unsigned long i = 1; i < numPoints; ++i) { - cairo_line_to(mCairo, (gfxFloat)points[i].x, (gfxFloat)points[i].y); + cairo_move_to(mCairo, points[0].x, points[0].y); + for (PRUint32 i = 1; i < numPoints; ++i) { + cairo_line_to(mCairo, points[i].x, points[i].y); } } @@ -194,6 +241,11 @@ void gfxContext::SetMatrix(const gfxMatrix& matrix) cairo_set_matrix(mCairo, &mat); } +void gfxContext::IdentityMatrix() +{ + cairo_identity_matrix(mCairo); +} + gfxMatrix gfxContext::CurrentMatrix() const { cairo_matrix_t mat; @@ -239,7 +291,26 @@ gfxContext::AntialiasMode gfxContext::CurrentAntialiasMode() return MODE_COVERAGE; } -void gfxContext::SetDash(gfxFloat* dashes, int ndash, gfxFloat offset) +void gfxContext::SetDash(gfxLineType ltype) +{ + static double dash[] = {5.0, 5.0}; + static double dot[] = {1.0, 1.0}; + + switch (ltype) { + case gfxLineDashed: + SetDash(dash, 2, 0.0); + break; + case gfxLineDotted: + SetDash(dot, 2, 0.0); + break; + case gfxLineSolid: + default: + SetDash(nsnull, 0, 0.0); + break; + } +} + +void gfxContext::SetDash(gfxFloat *dashes, int ndash, gfxFloat offset) { cairo_set_dash(mCairo, dashes, ndash, offset); } @@ -321,7 +392,7 @@ void gfxContext::SetColor(const gfxRGBA& c) cairo_set_source_rgba(mCairo, c.r, c.g, c.b, c.a); } -void gfxContext::SetPattern(gfxPattern* pattern) +void gfxContext::SetPattern(gfxPattern *pattern) { cairo_set_source(mCairo, pattern->CairoPattern()); } diff --git a/gfx/thebes/src/gfxImageSurface.cpp b/gfx/thebes/src/gfxImageSurface.cpp index 9327cbff2581..f9a4d0e47273 100644 --- a/gfx/thebes/src/gfxImageSurface.cpp +++ b/gfx/thebes/src/gfxImageSurface.cpp @@ -35,24 +35,55 @@ * * ***** END LICENSE BLOCK ***** */ +#include + #include "gfxImageSurface.h" THEBES_IMPL_REFCOUNTING(gfxImageSurface) -gfxImageSurface::gfxImageSurface(int format, long width, long height) : +gfxImageSurface::gfxImageSurface(gfxImageFormat format, long width, long height) : mFormat(format), mWidth(width), mHeight(height) { - mData = new unsigned char[width * height * 4]; + long stride = Stride(); + mData = new unsigned char[height * stride]; - Init(cairo_image_surface_create_for_data((unsigned char*)mData, - CAIRO_FORMAT_ARGB32, - width, - height, - width * 4)); + //memset(mData, 0xff, height*stride); + cairo_surface_t *surface = + cairo_image_surface_create_for_data((unsigned char*)mData, + (cairo_format_t)format, + width, + height, + stride); + Init(surface); } gfxImageSurface::~gfxImageSurface() { + Destroy(); + delete[] mData; } + +long +gfxImageSurface::Stride() const +{ + long stride; + + if (mFormat == ImageFormatARGB32) + stride = mWidth * 4; + else if (mFormat == ImageFormatRGB24) + stride = mWidth * 3; + else if (mFormat == ImageFormatA8) + stride = mWidth; + else if (mFormat == ImageFormatA1) { + stride = (mWidth + 7) / 8; + } else { + NS_WARNING("Unknown format specified to gfxImageSurface!"); + stride = mWidth * 4; + } + + stride = ((stride + 3) / 4) * 4; + + return stride; +} diff --git a/gfx/thebes/src/gfxXlibSurface.cpp b/gfx/thebes/src/gfxXlibSurface.cpp index 813b0e89b4c3..0ef68c55ec0a 100644 --- a/gfx/thebes/src/gfxXlibSurface.cpp +++ b/gfx/thebes/src/gfxXlibSurface.cpp @@ -20,6 +20,7 @@ * * Contributor(s): * Stuart Parmenter + * Vladimir Vukicevic * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -39,12 +40,52 @@ THEBES_IMPL_REFCOUNTING(gfxXlibSurface) -gfxXlibSurface::gfxXlibSurface(Display *dpy, Drawable drawable, - Visual *visual) +gfxXlibSurface::gfxXlibSurface(Display* dpy, Drawable drawable, Visual* visual) : + mOwnsPixmap(PR_FALSE), mDisplay(dpy), mDrawable(drawable) { - Init(cairo_xlib_surface_create(display, drawable, visual, CAIRO_FORMAT_ARGB32); + // figure out width/height/depth + Window root_ignore; + int x_ignore, y_ignore; + unsigned int bwidth_ignore, width, height, depth; + + XGetGeometry(dpy, + drawable, + &root_ignore, &x_ignore, &y_ignore, + &width, &height, + &bwidth_ignore, &depth); + + mWidth = width; + mHeight = height; + + cairo_surface_t *surf = cairo_xlib_surface_create(dpy, drawable, visual, width, height); + Init(surf); +} + +gfxXlibSurface::gfxXlibSurface(Display* dpy, Drawable drawable, Visual* visual, + unsigned long width, unsigned long height) : + mOwnsPixmap(PR_FALSE), mDisplay(dpy), mDrawable(drawable), mWidth(width), mHeight(height) +{ + cairo_surface_t *surf = cairo_xlib_surface_create(dpy, drawable, visual, width, height); + Init(surf); +} + +gfxXlibSurface::gfxXlibSurface(Display* dpy, Visual* visual, unsigned long width, unsigned long height) : + mOwnsPixmap(PR_TRUE), mDisplay(dpy), mWidth(width), mHeight(height) + +{ + mDrawable = (Drawable)XCreatePixmap(dpy, + RootWindow(dpy, DefaultScreen(dpy)), + width, height, + DefaultDepth(dpy, DefaultScreen(dpy))); + + cairo_surface_t *surf = cairo_xlib_surface_create(dpy, pixmap, visual, width, height); + Init(surf); } gfxXlibSurface::~gfxXlibSurface() { + Destroy(); + + if (mOwnsPixmap) + XFreePixmap(mDisplay, mDrawable); }