Closed Bug 550475 Opened 14 years ago Closed 3 years ago

Cairo D2D code should use automatic pointers

Categories

(Core :: Graphics, defect)

1.9.2 Branch
x86
Windows 7
defect
Not set
normal

Tracking

()

RESOLVED FIXED

People

(Reporter: bas.schouten, Assigned: bas.schouten)

Details

Attachments

(2 files, 2 obsolete files)

Attached patch Add a RefPtr class to cairo (obsolete) — Splinter Review
Management of the different COM objects in Cairo code has become very tricky. We should use automatic pointers to make sure we don't leak objects, and clean up the countless releases and addrefs in the code.

Two things need to happen:
1. A smart RefPtr template class needs to be added.
2. It needs to be integrated into Cairo D2D, to do this we need to manually call the constructor and destructor since we cannot use new to allocate our structure, since cairo controls the freeing.
Attachment #430627 - Flags: review?(jmuizelaar)
Here's the code to use the RefPtr. It all seems to work well! But these things are tricky, I might have made mistakes.
Attachment #430628 - Flags: review?(jmuizelaar)
Wouldn't this (attachment 430627 [details] [diff] [review]) be the first C++ code in cairo? I thought that so far it was plain C. Or do you want to add that into the Mozilla tree only and not upstream?
(In reply to comment #2)
> Wouldn't this (attachment 430627 [details] [diff] [review]) be the first C++ code in cairo? I thought
> that so far it was plain C. Or do you want to add that into the Mozilla tree
> only and not upstream?

The QPainter backend is C++ as well. And the rest of the D2D backend is C++.
Comment on attachment 430627 [details] [diff] [review]
Add a RefPtr class to cairo

Some comments

>+
>+    template <class newType>
>+    RefPtr(const RefPtr<newType> &aRefPtr)
>+    {
>+	mPtr = aRefPtr.get();
>+	if (mPtr) {
>+	    mPtr->AddRef();
>+	}
>+    }
What does this one do?


>+    ~RefPtr()
>+    {
>+	DWORD test;
>+	if (mPtr) {
>+	    test = mPtr->Release();
>+	}
>+    }
What's 'test' for?

>+
>+    RefPtr<T> &operator =(const RefPtr<T> aPtr)
>+    {
>+	mPtr = aPtr.mPtr;
>+	if (mPtr) {
>+	    mPtr->AddRef();
>+	}
>+	return *this;
>+    }
Won't this one leak?

>+    
>+    RefPtr<T> &operator =(T* aPtr)
>+    {
>+	if (mPtr) {
>+	    mPtr->Release();
>+	}
>+	mPtr = aPtr;
>+	if (mPtr) {
>+	    mPtr->AddRef();
>+	}
>+	return *this;
>+    }
>+
>+    /** 
>+     * WARNING for ease of use, passing a reference will release/clear out ptr!
>+     * We null out the ptr before returning its address so people passing byref
>+     * as input will most likely get APIs returning errors rather than accessing
>+     * freed memory. Further more accessing it after this point if it hasn't
>+     * been set will produce a null pointer dereference.
>+     */

I don't think the usage of 'APIs' is correct here.
(In reply to comment #4)
> (From update of attachment 430627 [details] [diff] [review])
> Some comments
> 
> >+
> >+    template <class newType>
> >+    RefPtr(const RefPtr<newType> &aRefPtr)
> >+    {
> >+	mPtr = aRefPtr.get();
> >+	if (mPtr) {
> >+	    mPtr->AddRef();
> >+	}
> >+    }
> What does this one do?

This allows the following:

RefPtr<Base>
Function()
{
  RefPtr<Child> child = new Child();
  return child;
}

As this will create the result using RefPtr<Base>(child). I believe.. correct me if I'm wrong.

> 
> 
> >+    ~RefPtr()
> >+    {
> >+	DWORD test;
> >+	if (mPtr) {
> >+	    test = mPtr->Release();
> >+	}
> >+    }
> What's 'test' for?
Left over debug cruft I used with a breakpoint to output if all releases were behaving as expected :).
> 
> >+
> >+    RefPtr<T> &operator =(const RefPtr<T> aPtr)
> >+    {
> >+	mPtr = aPtr.mPtr;
> >+	if (mPtr) {
> >+	    mPtr->AddRef();
> >+	}
> >+	return *this;
> >+    }
> Won't this one leak?

You're absolutely right.
Comment on attachment 430627 [details] [diff] [review]
Add a RefPtr class to cairo


>+    template <class newType>
>+    RefPtr(const RefPtr<newType> &aRefPtr)
>+    {
>+	mPtr = aRefPtr.get();
>+	if (mPtr) {
>+	    mPtr->AddRef();
>+	}
>+    }

This really makes me uneasy. I don't like adding the ability to use extra types automatically in RefPtr; it's going to lead to bizarre compile errors. IMO, remove it.
(In reply to comment #6)
> (From update of attachment 430627 [details] [diff] [review])
> 
> >+    template <class newType>
> >+    RefPtr(const RefPtr<newType> &aRefPtr)
> >+    {
> >+	mPtr = aRefPtr.get();
> >+	if (mPtr) {
> >+	    mPtr->AddRef();
> >+	}
> >+    }
> 
> This really makes me uneasy. I don't like adding the ability to use extra types
> automatically in RefPtr; it's going to lead to bizarre compile errors. IMO,
> remove it.

I can understand, but it's the best way to deal with functions like create_brush which returns an ID2D1Brush from potentially a ID2D1SolidColorBrush or ID2D1BitmapBrush or one of the others. I don't think the compile errors will be that bad. If you know how to read template compile errors, that is ;).
Well, can you at least make that constructor explicit?
Comment on attachment 430627 [details] [diff] [review]
Add a RefPtr class to cairo

In addition to the previous comments here are some more:

I'm not sure what we want the style of this thing to be. We could go with a 
more cairo-like style and call it scoped_refptr. On the other hand it will probably only be used in the d2d and dwrite backends so perhaps RefPtr matches that style better? We could also call it COMPtr or ComPtr or something like that...

>+    RefPtr<T> &operator =(T* aPtr)
>+    {
>+	if (mPtr) {
>+	    mPtr->Release();
>+	}
>+	mPtr = aPtr;
>+	if (mPtr) {
>+	    mPtr->AddRef();
>+	}
>+	return *this;
>+    }

This breaks if doing self assignment.
Attachment #430627 - Flags: review?(jmuizelaar) → review-
(In reply to comment #8)
> Well, can you at least make that constructor explicit?

Sure!

(In reply to comment #9)
> (From update of attachment 430627 [details] [diff] [review])
> In addition to the previous comments here are some more:
> 
> I'm not sure what we want the style of this thing to be. We could go with a 
> more cairo-like style and call it scoped_refptr. On the other hand it will
> probably only be used in the d2d and dwrite backends so perhaps RefPtr matches
> that style better? We could also call it COMPtr or ComPtr or something like
> that...

Yeah, I was thinking such things. And I decided on RefPtr, I'm completely open to any other name. I like CamelCasing I guess :p.

> 
> >+    RefPtr<T> &operator =(T* aPtr)
> >+    {
> >+	if (mPtr) {
> >+	    mPtr->Release();
> >+	}
> >+	mPtr = aPtr;
> >+	if (mPtr) {
> >+	    mPtr->AddRef();
> >+	}
> >+	return *this;
> >+    }
> 
> This breaks if doing self assignment.
I'll fix this assignment operator to allow

RefPtr<Class> test = new Class();
test = test.get();

And I'll fix the other assignment operator to not leak as you mentioned and to allow:
test = test;
Process earlier comments. We're having some memory issues with D2D and I'd like to get the auto-pointers and investigate from there.
Attachment #430627 - Attachment is obsolete: true
Attachment #433772 - Flags: review?(jmuizelaar)
Updated for the latest backend version.
Attachment #430628 - Attachment is obsolete: true
Attachment #433773 - Flags: review?(jmuizelaar)
Attachment #430628 - Flags: review?(jmuizelaar)
Comment on attachment 433772 [details] [diff] [review]
Part 1: Add a RefPtr class to cairo v2

>diff --git a/gfx/cairo/cairo/src/cairo-win32-refptr.h b/gfx/cairo/cairo/src/cairo-win32-refptr.h
>new file mode 100644
>--- /dev/null
>+++ b/gfx/cairo/cairo/src/cairo-win32-refptr.h
>+    RefPtr<T> &operator =(const RefPtr<T> aPtr)
>+    {
>+	T* oldPtr = mPtr;
>+	mPtr = aPtr.mPtr;
>+	if (mPtr) {
>+	    mPtr->AddRef();
>+	}
>+	if (oldPtr) {
>+	    oldPtr->Release();
>+	}
>+	return *this;
>+    }
>+    
>+    RefPtr<T> &operator =(T* aPtr)
>+    {
>+	T *oldPtr = mPtr;
>+	mPtr = aPtr;
>+	if (mPtr) {
>+	    mPtr->AddRef();
>+	}
>+	if (oldPtr) {
>+	    oldPtr->Release();
>+	}
>+	return *this;
>+    }

These two could maybe share code.
Attachment #433772 - Flags: review?(jmuizelaar) → review+
Comment on attachment 433773 [details] [diff] [review]
Part 2: Use RefPtr class in cairo-d2d-surface v2

>diff --git a/gfx/cairo/cairo/src/cairo-d2d-private.h b/gfx/cairo/cairo/src/cairo-d2d-private.h
>--- a/gfx/cairo/cairo/src/cairo-d2d-private.h
>+++ b/gfx/cairo/cairo/src/cairo-d2d-private.h
>@@ -42,56 +42,66 @@
> #include <d2d1.h>
> #include <d3d10.h>
> #include <dxgi.h>
> 
> extern "C" {
> #include "cairoint.h"
> }
> 
>+#include "cairo-win32-refptr.h"
>+
> struct _cairo_d2d_surface {
>+    _cairo_d2d_surface() : clipRect(NULL), clipping(false), isDrawing(false),
>+	textRenderingInit(true)
>+    { }
>+    ~_cairo_d2d_surface()
>+    {
>+	delete clipRect;
>+    }
>+
>     cairo_surface_t base;
>     /** Render target of the texture we render to */
>-    ID2D1RenderTarget *rt;
>+    RefPtr<ID2D1RenderTarget> rt;
>     /** Surface containing our backstore */
>-    ID3D10Resource *surface;
>+    RefPtr<ID3D10Resource> surface;
>     /** 
>      * Surface used to temporarily store our surface if a bitmap isn't available
>      * straight from our render target surface.
>      */
>-    ID3D10Texture2D *bufferTexture;
>+    RefPtr<ID3D10Texture2D> bufferTexture;
>     /** Backbuffer surface hwndrt renders to (NULL if not a window surface) */
>-    IDXGISurface *backBuf;
>+    RefPtr<IDXGISurface> backBuf;
>     /** Bitmap shared with texture and rendered to by rt */
>-    ID2D1Bitmap *surfaceBitmap;
>+    RefPtr<ID2D1Bitmap> surfaceBitmap;
>     /** Swap chain holding our backbuffer (NULL if not a window surface) */
>-    IDXGISwapChain *dxgiChain;
>+    RefPtr<IDXGISwapChain> dxgiChain;
>     /** Window handle of the window we belong to */
>     HWND hwnd;
>     /** Format of the surface */
>     cairo_format_t format;
>     /** Geometry used for clipping when complex clipping is required */
>-    ID2D1Geometry *clipMask;
>+    RefPtr<ID2D1Geometry> clipMask;
>     /** Clip rectangle for axis aligned rectangular clips */
>     D2D1_RECT_F *clipRect;
>     /** Clip layer used for pushing geometry clip mask */
>-    ID2D1Layer *clipLayer;
>+    RefPtr<ID2D1Layer> clipLayer;
>     /** Mask layer used by surface_mask to push opacity masks */
>-    ID2D1Layer *maskLayer;
>+    RefPtr<ID2D1Layer> maskLayer;
>     /**
>      * Layer used for clipping when tiling, and also for clearing out geometries
>      * - lazily initialized 
>      */
>-    ID2D1Layer *helperLayer;
>+    RefPtr<ID2D1Layer> helperLayer;
>     /** If this layer currently is clipping, used to prevent excessive push/pops */
>     bool clipping;
>     /** Brush used for bitmaps */
>-    ID2D1BitmapBrush *bitmapBrush;
>+    RefPtr<ID2D1BitmapBrush> bitmapBrush;
>     /** Brush used for solid colors */
>-    ID2D1SolidColorBrush *solidColorBrush;
>+    RefPtr<ID2D1SolidColorBrush> solidColorBrush;
>     /** Indicates if our render target is currently in drawing mode */
>     bool isDrawing;
>     /** Indicates if text rendering is initialized */
>     bool textRenderingInit;
> };
> typedef struct _cairo_d2d_surface cairo_d2d_surface_t;
> 
> typedef HRESULT (WINAPI*D2D1CreateFactoryFunc)(
>@@ -205,17 +215,17 @@ public:
> 	}
> 	return mDeviceInstance;
>     }
> private:
>     static ID3D10Device1 *mDeviceInstance;
> };
> 
> 
>-ID2D1Brush*
>+RefPtr<ID2D1Brush>
> _cairo_d2d_create_brush_for_pattern(cairo_d2d_surface_t *d2dsurf, 
> 			            const cairo_pattern_t *pattern,
> 				    unsigned int lastrun,
> 				    unsigned int *runs_remaining,
> 				    bool *pushed_clip,
> 				    bool unique = false);
> #endif /* CAIRO_HAS_D2D_SURFACE */
> #endif /* CAIRO_D2D_PRIVATE_H */
>diff --git a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
>--- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
>+++ b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
>@@ -39,16 +39,18 @@
> #include "cairo-d2d-private.h"
> #include "cairo-dwrite-private.h"
> 
> extern "C" {
> #include "cairo-win32.h"
> #include "cairo-analysis-surface-private.h"
> }
> 
>+// Required for using placement new.
>+#include <new>
> 
> ID2D1Factory *D2DSurfFactory::mFactoryInstance = NULL;
> ID3D10Device1 *D3D10Factory::mDeviceInstance = NULL;
> 
> #define CAIRO_INT_STATUS_SUCCESS (cairo_int_status_t)CAIRO_STATUS_SUCCESS
> 
> /**
>  * Create a similar surface which will blend effectively to
>@@ -384,32 +386,31 @@ _cairo_d2d_get_buffer_texture(cairo_d2d_
>  */
> static void _cairo_d2d_update_surface_bitmap(cairo_d2d_surface_t *d2dsurf)
> {
>     if (!d2dsurf->backBuf) {
> 	return;
>     }
>     ID3D10Texture2D *texture = _cairo_d2d_get_buffer_texture(d2dsurf);
>     if (!d2dsurf->surfaceBitmap) {
>-	IDXGISurface *dxgiSurface;
>+	RefPtr<IDXGISurface> dxgiSurface;
> 	D2D1_ALPHA_MODE alpha;
> 	if (d2dsurf->base.content == CAIRO_CONTENT_COLOR) {
> 	    alpha = D2D1_ALPHA_MODE_IGNORE;
> 	} else {
> 	    alpha = D2D1_ALPHA_MODE_PREMULTIPLIED;
> 	}
>         /** Using DXGI_FORMAT_UNKNOWN will automatically use the texture's format. */
> 	D2D1_BITMAP_PROPERTIES bitProps = D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN,
> 										   alpha));
> 	texture->QueryInterface(&dxgiSurface);
> 	d2dsurf->rt->CreateSharedBitmap(IID_IDXGISurface,
> 					dxgiSurface,
> 					&bitProps,
> 					&d2dsurf->surfaceBitmap);
>-	dxgiSurface->Release();
>     }
>     D3D10Factory::Device()->CopyResource(texture, d2dsurf->surface);
> }
> 
> /**
>  * Present the backbuffer for a surface create for an HWND. This needs
>  * to be called when the owner of the original window surface wants to
>  * actually present the executed drawing operations to the screen.
>@@ -522,17 +523,17 @@ _cairo_d2d_matrix_from_matrix(const cair
> 
> /**
>  * Create a D2D stroke style interface for a cairo stroke style object. Must be
>  * released when the calling function is finished with it.
>  *
>  * \param style Cairo stroke style object
>  * \return D2D StrokeStyle interface
>  */
>-static ID2D1StrokeStyle*
>+static RefPtr<ID2D1StrokeStyle>
> _cairo_d2d_create_strokestyle_for_stroke_style(const cairo_stroke_style_t *style)
> {
>     D2D1_CAP_STYLE line_cap = D2D1_CAP_STYLE_FLAT;
>     switch (style->line_cap) {
> 	case CAIRO_LINE_CAP_BUTT:
> 	    line_cap = D2D1_CAP_STYLE_FLAT;
> 	    break;
> 	case CAIRO_LINE_CAP_SQUARE:
>@@ -564,17 +565,17 @@ _cairo_d2d_create_strokestyle_for_stroke
> 	}
>     }
> 
>     D2D1_DASH_STYLE dashStyle = D2D1_DASH_STYLE_SOLID;
>     if (dashes) {
> 	dashStyle = D2D1_DASH_STYLE_CUSTOM;
>     }
> 
>-    ID2D1StrokeStyle *strokeStyle;
>+    RefPtr<ID2D1StrokeStyle> strokeStyle;
>     D2DSurfFactory::Instance()->CreateStrokeStyle(D2D1::StrokeStyleProperties(line_cap, 
> 									      line_cap,
> 									      line_cap, 
> 									      line_join, 
> 									      (FLOAT)style->miter_limit,
> 									      dashStyle,
> 									      (FLOAT)style->dash_offset),
> 						  dashes,
>@@ -583,33 +584,32 @@ _cairo_d2d_create_strokestyle_for_stroke
>     delete [] dashes;
>     return strokeStyle;
> }
> 
> cairo_user_data_key_t bitmap_key;
> 
> struct cached_bitmap {
>     /** The cached bitmap */
>-    ID2D1Bitmap *bitmap;
>+    RefPtr<ID2D1Bitmap> bitmap;
>     /** The cached bitmap was created with a transparent rectangle around it */
>     bool isNoneExtended;
>     /** The cached bitmap is dirty and needs its data refreshed */
>     bool dirty;
>     /** Order of snapshot detach/release bitmap called not guaranteed, single threaded refcount for now */
>     int refs;
> };
> 
> /** 
>  * This is called when user data on a surface is replaced or the surface is
>  * destroyed.
>  */
> static void _d2d_release_bitmap(void *bitmap)
> {
>     cached_bitmap *bitmp = (cached_bitmap*)bitmap;
>-    bitmp->bitmap->Release();
>     if (!--bitmp->refs) {
> 	delete bitmap;

looks like we're calling delete on the wrong object here, and so we'd leak bitmp->bitmap.
you should probably use better names than bitmap/bitmp.

>     }
> }
> 
> /**
>  * Via a little trick this is just used to determine when a surface has been
>  * modified.
>@@ -636,45 +636,44 @@ static void _d2d_snapshot_detached(cairo
>  *
>  * \param d2dsurf Surface to create a brush for
>  * \param pattern The pattern to create a brush for
>  * \param unique We cache the bitmap/color brush for speed. If this
>  * needs a brush that is unique (i.e. when more than one is needed),
>  * this will make the function return a seperate brush.
>  * \return A brush object
>  */
>-ID2D1Brush*
>+RefPtr<ID2D1Brush>
> _cairo_d2d_create_brush_for_pattern(cairo_d2d_surface_t *d2dsurf, 
> 				    const cairo_pattern_t *pattern,
> 				    unsigned int last_run,
> 				    unsigned int *remaining_runs,
> 				    bool *pushed_clip,
> 				    bool unique)
> {
>     *remaining_runs = 1;
>     *pushed_clip = false;
> 
>     if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
> 	cairo_solid_pattern_t *sourcePattern =
> 	    (cairo_solid_pattern_t*)pattern;
> 	D2D1_COLOR_F color = _cairo_d2d_color_from_cairo_color(sourcePattern->color);
> 	if (unique) {
>-	    ID2D1SolidColorBrush *brush;
>+	    RefPtr<ID2D1SolidColorBrush> brush;
> 	    d2dsurf->rt->CreateSolidColorBrush(color,
> 					       &brush);
> 	    *remaining_runs = 0;
> 	    return brush;
> 	} else {
> 	    if (d2dsurf->solidColorBrush->GetColor().a != color.a ||
> 		d2dsurf->solidColorBrush->GetColor().r != color.r ||
> 		d2dsurf->solidColorBrush->GetColor().g != color.g ||
> 		d2dsurf->solidColorBrush->GetColor().b != color.b) {
> 		d2dsurf->solidColorBrush->SetColor(color);
> 	    }
>-	    d2dsurf->solidColorBrush->AddRef();
> 	    *remaining_runs = 0;
> 	    return d2dsurf->solidColorBrush;
> 	}
> 
>     } else if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) {
> 	cairo_matrix_t mat = pattern->matrix;
> 	/**
> 	 * Cairo views this matrix as the transformation of the destination
>@@ -690,26 +689,25 @@ _cairo_d2d_create_brush_for_pattern(cair
> 
> 	D2D1_GRADIENT_STOP *stops = 
> 	    new D2D1_GRADIENT_STOP[sourcePattern->base.n_stops];
> 	for (unsigned int i = 0; i < sourcePattern->base.n_stops; i++) {
> 	    stops[i].position = (FLOAT)sourcePattern->base.stops[i].offset;
> 	    stops[i].color = 
> 		_cairo_d2d_color_from_cairo_color(sourcePattern->base.stops[i].color);
> 	}
>-	ID2D1GradientStopCollection *stopCollection;
>+	RefPtr<ID2D1GradientStopCollection> stopCollection;
> 	d2dsurf->rt->CreateGradientStopCollection(stops, sourcePattern->base.n_stops, &stopCollection);
>-	ID2D1LinearGradientBrush *brush;
>+	RefPtr<ID2D1LinearGradientBrush> brush;
> 	d2dsurf->rt->CreateLinearGradientBrush(D2D1::LinearGradientBrushProperties(_d2d_point_from_cairo_point(&sourcePattern->p1),
> 										   _d2d_point_from_cairo_point(&sourcePattern->p2)),
> 					       brushProps,
> 					       stopCollection,
> 					       &brush);
> 	delete [] stops;
>-	stopCollection->Release();
> 	*remaining_runs = 0;
> 	return brush;
> 
>     } else if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL) {
> 	cairo_matrix_t mat = pattern->matrix;
> 	cairo_matrix_invert(&mat);
> 
> 	D2D1_BRUSH_PROPERTIES brushProps =
>@@ -735,28 +733,27 @@ _cairo_d2d_create_brush_for_pattern(cair
> 
> 	D2D1_GRADIENT_STOP *stops = 
> 	    new D2D1_GRADIENT_STOP[sourcePattern->base.n_stops];
> 	for (unsigned int i = 0; i < sourcePattern->base.n_stops; i++) {
> 	    stops[i].position = (FLOAT)sourcePattern->base.stops[i].offset;
> 	    stops[i].color = 
> 		_cairo_d2d_color_from_cairo_color(sourcePattern->base.stops[i].color);
> 	}
>-	ID2D1GradientStopCollection *stopCollection;
>+	RefPtr<ID2D1GradientStopCollection> stopCollection;
> 	d2dsurf->rt->CreateGradientStopCollection(stops, sourcePattern->base.n_stops, &stopCollection);
>-	ID2D1RadialGradientBrush *brush;
>+	RefPtr<ID2D1RadialGradientBrush> brush;
> 
> 	d2dsurf->rt->CreateRadialGradientBrush(D2D1::RadialGradientBrushProperties(center,
> 										   origin,
> 										   _cairo_fixed_to_float(sourcePattern->r2),
> 										   _cairo_fixed_to_float(sourcePattern->r2)),
> 					       brushProps,
> 					       stopCollection,
> 					       &brush);
>-	stopCollection->Release();
> 	delete [] stops;
> 	*remaining_runs = 0;
> 	return brush;
> 
>     } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
> 	cairo_matrix_t mat = pattern->matrix;
> 	cairo_matrix_invert(&mat);
> 
>@@ -839,31 +836,30 @@ _cairo_d2d_create_brush_for_pattern(cair
> 		xoffset = current_horiz_tile * maxSize;
> 		yoffset = current_vert_tile * maxSize;
> 		*remaining_runs = horiz_tiles * vert_tiles - last_run - 1;
> 		width = min(maxSize, srcSurf->width - maxSize * current_horiz_tile);
> 		height = min(maxSize, srcSurf->height - maxSize * current_vert_tile);
> 		// Move the image to the right spot.
> 		cairo_matrix_translate(&mat, xoffset, yoffset);
> 		if (true) {
>-		    ID2D1RectangleGeometry *clipRect;
>+		    RefPtr<ID2D1RectangleGeometry> clipRect;
> 		    D2DSurfFactory::Instance()->CreateRectangleGeometry(D2D1::RectF(0, 0, (float)width, (float)height),
> 									&clipRect);
> 
> 		    if (!d2dsurf->helperLayer) {
> 			d2dsurf->rt->CreateLayer(&d2dsurf->helperLayer);
> 		    }
> 		    
> 		    d2dsurf->rt->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(),
> 								 clipRect,
> 								 D2D1_ANTIALIAS_MODE_PER_PRIMITIVE,
> 								 _cairo_d2d_matrix_from_matrix(&mat)),
> 					   d2dsurf->helperLayer);
> 		    *pushed_clip = true;
>-		    clipRect->Release();
> 		}
> 	    } else {
> 		width = srcSurf->width;
> 		height = srcSurf->height;
> 	    }
> 
> 	    cached_bitmap *cachebitmap = NULL;
> 	    if (!tiled) {
>@@ -963,17 +959,17 @@ _cairo_d2d_create_brush_for_pattern(cair
> 						   extendMode,
> 						   D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR);
> 	} else {
> 	    bitProps = D2D1::BitmapBrushProperties(extendMode,
> 						   extendMode,
> 						   D2D1_BITMAP_INTERPOLATION_MODE_LINEAR);
> 	}
> 	if (unique) {
>-	    ID2D1BitmapBrush *bitBrush;
>+	    RefPtr<ID2D1BitmapBrush> bitBrush;
> 	    D2D1_BRUSH_PROPERTIES brushProps =
> 		D2D1::BrushProperties(1.0, _cairo_d2d_matrix_from_matrix(&mat));
> 	    d2dsurf->rt->CreateBitmapBrush(sourceBitmap, 
> 					   &bitProps,
> 					   &brushProps,
> 					   &bitBrush);
> 	    return bitBrush;
> 	} else {
>@@ -994,17 +990,16 @@ _cairo_d2d_create_brush_for_pattern(cair
> 	    } else {
> 		D2D1_BRUSH_PROPERTIES brushProps =
> 		    D2D1::BrushProperties(1.0, _cairo_d2d_matrix_from_matrix(&mat));
> 		d2dsurf->rt->CreateBitmapBrush(sourceBitmap,
> 					       &bitProps,
> 					       &brushProps,
> 					       &d2dsurf->bitmapBrush);
> 	    }
>-	    d2dsurf->bitmapBrush->AddRef();
> 	    return d2dsurf->bitmapBrush;
> 	}
>     } else {
> 	return NULL;
>     }
> }
> 
> 
>@@ -1098,24 +1093,24 @@ _cairo_d2d_path_close(void *closure)
> /**
>  * Create an ID2D1PathGeometry for a cairo_path_fixed_t
>  *
>  * \param path Path to create a geometry for
>  * \param fill_rule Fill rule to use
>  * \param type Figure begin type to use
>  * \return A D2D geometry
>  */
>-static ID2D1PathGeometry*
>+static RefPtr<ID2D1PathGeometry>
> _cairo_d2d_create_path_geometry_for_path(cairo_path_fixed_t *path, 
> 					 cairo_fill_rule_t fill_rule,
> 					 D2D1_FIGURE_BEGIN type)
> {
>-    ID2D1PathGeometry *d2dpath;
>+    RefPtr<ID2D1PathGeometry> d2dpath;
>     D2DSurfFactory::Instance()->CreatePathGeometry(&d2dpath);
>-    ID2D1GeometrySink *sink;
>+    RefPtr<ID2D1GeometrySink> sink;
>     d2dpath->Open(&sink);
>     D2D1_FILL_MODE fillMode = D2D1_FILL_MODE_WINDING;
>     if (fill_rule == CAIRO_FILL_RULE_WINDING) {
> 	fillMode = D2D1_FILL_MODE_WINDING;
>     } else if (fill_rule == CAIRO_FILL_RULE_EVEN_ODD) {
> 	fillMode = D2D1_FILL_MODE_ALTERNATE;
>     }
>     sink->SetFillMode(fillMode);
>@@ -1130,17 +1125,16 @@ _cairo_d2d_create_path_geometry_for_path
> 				_cairo_d2d_path_line_to,
> 				_cairo_d2d_path_curve_to,
> 				_cairo_d2d_path_close,
> 				&pathConvert);
>     if (pathConvert.figureActive) {
> 	sink->EndFigure(D2D1_FIGURE_END_OPEN);
>     }
>     sink->Close();
>-    sink->Release();
>     return d2dpath;
> }
> 
> /**
>  * We use this to clear out a certain path on a surface. This will respect
>  * the existing clip.
>  *
>  * \param d2dsurf Surface we clear
>@@ -1157,21 +1151,21 @@ static void _cairo_d2d_clear_geometry(ca
> 	/**
> 	 * We have an axis aligned rectangular clip and no pathGeometry, we can
> 	 * just clear the surface.
> 	 */
> 	d2dsurf->rt->Clear(D2D1::ColorF(0, 0));
> 	return;
>     }
> 
>-    IDXGISurface *dxgiSurface;
>-    ID2D1Bitmap *bitmp;
>+    RefPtr<IDXGISurface> dxgiSurface;
>+    RefPtr<ID2D1Bitmap> bitmp;
> 
>     /** Create a temporary buffer for our surface content */
>-    ID3D10Texture2D *bufTexture = _cairo_d2d_get_buffer_texture(d2dsurf);
>+    RefPtr<ID3D10Texture2D> bufTexture = _cairo_d2d_get_buffer_texture(d2dsurf);
> 
>     /** Copy our contents into the temporary buffer */
>     D3D10Factory::Device()->CopyResource(bufTexture, d2dsurf->surface);
> 
>     /** Make the temporary buffer available as a D2D Bitmap */
>     bufTexture->QueryInterface(&dxgiSurface);
>     D2D1_BITMAP_PROPERTIES props = D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM,
> 									    D2D1_ALPHA_MODE_PREMULTIPLIED));
>@@ -1181,43 +1175,40 @@ static void _cairo_d2d_clear_geometry(ca
> 						 &bitmp);
> 
>     /** Clear our original surface */
>     d2dsurf->rt->Clear(D2D1::ColorF(0, 0));
> 
>     DXGI_SURFACE_DESC desc;
>     dxgiSurface->GetDesc(&desc);
> 
>-    ID2D1RectangleGeometry *rectGeom;
>-    ID2D1PathGeometry *inverse;
>-    ID2D1Geometry *clearGeometry;
>-    ID2D1GeometrySink *sink;
>+    RefPtr<ID2D1RectangleGeometry> rectGeom;
>+    RefPtr<ID2D1PathGeometry> inverse;
>+    RefPtr<ID2D1Geometry> clearGeometry;
>+    RefPtr<ID2D1GeometrySink> sink;
> 
>     if (!d2dsurf->clipMask) {
> 	/** No clip mask, our clear geometry is equal to our path geometry. */
> 	clearGeometry = pathGeometry;
>-	clearGeometry->AddRef();
>     } else if (!pathGeometry) {
> 	/** No path geometry, our clear geometry is equal to our clip mask. */
> 	clearGeometry = d2dsurf->clipMask;
>-	clearGeometry->AddRef();
>     } else {
> 	/**
> 	 * A clipping mask and a pathGeometry, the intersect of the two
> 	 * geometries is the area of the surface that we want to clear.
> 	 */
>-	ID2D1PathGeometry *clipPathUnion;
>+	RefPtr<ID2D1PathGeometry> clipPathUnion;
> 	D2DSurfFactory::Instance()->CreatePathGeometry(&clipPathUnion);
> 	clipPathUnion->Open(&sink);
> 	pathGeometry->CombineWithGeometry(d2dsurf->clipMask,
> 					  D2D1_COMBINE_MODE_INTERSECT,
> 					  D2D1::IdentityMatrix(),
> 					  sink);
> 	sink->Close();
>-	sink->Release();
> 	clearGeometry = clipPathUnion;
>     }
> 
>     if (d2dsurf->clipMask) {
> 	/** If we have a clip mask, we'll need to pop the surface clip */
> 	_cairo_d2d_surface_pop_clip(d2dsurf);
>     }
> 
>@@ -1225,30 +1216,23 @@ static void _cairo_d2d_clear_geometry(ca
>      * Calculate the inverse of the geometry to clear. This is the clip mask
>      * when drawing our original content back to the surface.
>      */
>     D2DSurfFactory::Instance()->CreatePathGeometry(&inverse);
>     inverse->Open(&sink);
>     D2DSurfFactory::Instance()->CreateRectangleGeometry(D2D1::RectF(0, 0, (FLOAT)desc.Width, (FLOAT)desc.Height), &rectGeom);
>     rectGeom->CombineWithGeometry(clearGeometry, D2D1_COMBINE_MODE_EXCLUDE, D2D1::IdentityMatrix(), sink);
>     sink->Close();
>-    sink->Release();
>-    rectGeom->Release();
>-    clearGeometry->Release();
> 
>     /** Clip by the inverse and draw our content back to the surface */
>     d2dsurf->rt->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(), inverse),
> 			   d2dsurf->helperLayer);
>     d2dsurf->rt->DrawBitmap(bitmp);
>     d2dsurf->rt->PopLayer();
> 
>-    bitmp->Release();
>-    dxgiSurface->Release();
>-    inverse->Release();
>-
>     if (d2dsurf->clipMask) {
> 	/** If we have a clip mask, we'll need to push back the surface clip */
> 	_cairo_d2d_surface_push_clip(d2dsurf);
>     }
> }
> 
> static cairo_operator_t _cairo_d2d_simplify_operator(cairo_operator_t op,
> 						     const cairo_pattern_t *source)
>@@ -1277,19 +1261,19 @@ static cairo_surface_t*
> _cairo_d2d_create_similar(void			*surface,
> 			  cairo_content_t	 content,
> 			  int			 width,
> 			  int			 height)
> {
>     cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
>     cairo_d2d_surface_t *newSurf = static_cast<cairo_d2d_surface_t*>(malloc(sizeof(cairo_d2d_surface_t)));
>     
>-    memset(newSurf, 0, sizeof(cairo_d2d_surface_t));
>+    new (newSurf) cairo_d2d_surface_t();
>+    _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, content);
> 
>-    _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, content);
> 
>     D2D1_SIZE_U sizePixels;
>     D2D1_SIZE_F size;
>     HRESULT hr;
> 
>     sizePixels.width = width;
>     sizePixels.height = height;
>     FLOAT dpiX;
>@@ -1316,147 +1300,101 @@ _cairo_d2d_create_similar(void			*surfac
> 								       dpiY);
> 
>     if (sizePixels.width < 1) {
> 	sizePixels.width = 1;
>     }
>     if (sizePixels.height < 1) {
> 	sizePixels.height = 1;
>     }
>-    IDXGISurface *oldDxgiSurface;
>+    RefPtr<IDXGISurface> oldDxgiSurface;
>     d2dsurf->surface->QueryInterface(&oldDxgiSurface);
>     DXGI_SURFACE_DESC origDesc;
> 
>     oldDxgiSurface->GetDesc(&origDesc);
>-    oldDxgiSurface->Release();
> 
>     CD3D10_TEXTURE2D_DESC desc(origDesc.Format,
> 			       sizePixels.width,
> 			       sizePixels.height);
> 
>     if (content == CAIRO_CONTENT_ALPHA) {
> 	desc.Format = DXGI_FORMAT_A8_UNORM;
>     }
> 
>     desc.MipLevels = 1;
>     desc.Usage = D3D10_USAGE_DEFAULT;
>     desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
>-    ID3D10Texture2D *texture;
>+    RefPtr<ID3D10Texture2D> texture;
>+    RefPtr<IDXGISurface> dxgiSurface;
> 
>     hr = D3D10Factory::Device()->CreateTexture2D(&desc, NULL, &texture);
>     if (FAILED(hr)) {
>-	goto FAIL_D3DTEXTURE;
>+	goto FAIL_CREATESIMILAR;
>     }
> 
>     newSurf->surface = texture;
> 
>     // Create the DXGI surface.
>-    IDXGISurface *dxgiSurface;
>     hr = newSurf->surface->QueryInterface(IID_IDXGISurface, (void**)&dxgiSurface);
>     if (FAILED(hr)) {
>-	goto FAIL_DXGISURFACE;
>+	goto FAIL_CREATESIMILAR;
>     }
>     hr = D2DSurfFactory::Instance()->CreateDxgiSurfaceRenderTarget(dxgiSurface,
> 								   props,
> 								   &newSurf->rt);
> 
>     if (FAILED(hr)) {
>-	goto FAIL_DXGIRT;
>+	goto FAIL_CREATESIMILAR;
>     }
> 
>     hr = newSurf->rt->CreateSharedBitmap(IID_IDXGISurface,
> 					 dxgiSurface,
> 					 &bitProps,
> 					 &newSurf->surfaceBitmap);
>     if (FAILED(hr)) {
>-	goto FAIL_SHAREDBITMAP;
>+	goto FAIL_CREATESIMILAR;
>     }
> 
>-    dxgiSurface->Release();
>-
>     newSurf->rt->CreateSolidColorBrush(D2D1::ColorF(0, 1.0), &newSurf->solidColorBrush);
> 
>     return reinterpret_cast<cairo_surface_t*>(newSurf);
> 
>-FAIL_SHAREDBITMAP:
>-    newSurf->rt->Release();
>-FAIL_DXGIRT:
>-    dxgiSurface->Release();
>-FAIL_DXGISURFACE:
>-    newSurf->surface->Release();
>-FAIL_D3DTEXTURE:
>+FAIL_CREATESIMILAR:
>+    /** Ensure we call our surfaces desctructor */
>+    newSurf->~cairo_d2d_surface_t();
>     free(newSurf);
>     return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
> }
> 
> static cairo_status_t
> _cairo_d2d_finish(void	    *surface)
> {
>     cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
>-    if (d2dsurf->rt) {
>-	d2dsurf->rt->Release();
>-    }
>-    if (d2dsurf->surfaceBitmap) {
>-	d2dsurf->surfaceBitmap->Release();
>-    }
>-    if (d2dsurf->backBuf) {
>-	d2dsurf->backBuf->Release();
>-    }
>-    if (d2dsurf->dxgiChain) {
>-	d2dsurf->dxgiChain->Release();
>-    }
>-    if (d2dsurf->clipMask) {
>-	d2dsurf->clipMask->Release();
>-    }
>-    if (d2dsurf->clipRect) {
>-	delete d2dsurf->clipRect;
>-    }
>-    if (d2dsurf->clipLayer) {
>-	d2dsurf->clipLayer->Release();
>-    }
>-    if (d2dsurf->maskLayer) {
>-	d2dsurf->maskLayer->Release();
>-    }
>-    if (d2dsurf->solidColorBrush) {
>-	d2dsurf->solidColorBrush->Release();
>-    }
>-    if (d2dsurf->bitmapBrush) {
>-	d2dsurf->bitmapBrush->Release();
>-    }
>-    if (d2dsurf->surface) {
>-	d2dsurf->surface->Release();
>-    }
>-    if (d2dsurf->helperLayer) {
>-	d2dsurf->helperLayer->Release();
>-    }
>-    if (d2dsurf->bufferTexture) {
>-	d2dsurf->bufferTexture->Release();
>-    }
>+    d2dsurf->~cairo_d2d_surface_t();
>     return CAIRO_STATUS_SUCCESS;
> }
> 
> static cairo_status_t
> _cairo_d2d_acquire_source_image(void                    *abstract_surface,
> 				cairo_image_surface_t  **image_out,
> 				void                   **image_extra)
> {
>     cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(abstract_surface);
>     _cairo_d2d_flush(d2dsurf);
> 
>     HRESULT hr;
>     D2D1_SIZE_U size = d2dsurf->rt->GetPixelSize();
> 
>-    ID3D10Texture2D *softTexture;
>+    RefPtr<ID3D10Texture2D> softTexture;
> 
>-    IDXGISurface *dxgiSurface;
>+    RefPtr<IDXGISurface> dxgiSurface;
>     d2dsurf->surface->QueryInterface(&dxgiSurface);
>     DXGI_SURFACE_DESC desc;
> 
>     dxgiSurface->GetDesc(&desc);
>-    dxgiSurface->Release();
> 
>     CD3D10_TEXTURE2D_DESC softDesc(desc.Format, desc.Width, desc.Height);
> 
>     /**
>      * We can't actually map our backing store texture, so we create one in CPU memory, and then
>      * tell D3D to copy the data from our surface there, readback is expensive, we -never-
>      * -ever- want this to happen.
>      */
>@@ -1469,26 +1407,25 @@ _cairo_d2d_acquire_source_image(void    
> 	return CAIRO_STATUS_NO_MEMORY;
>     }
> 
>     D3D10Factory::Device()->CopyResource(softTexture, d2dsurf->surface);
> 
>     D3D10_MAPPED_TEXTURE2D data;
>     hr = softTexture->Map(0, D3D10_MAP_READ_WRITE, 0, &data);
>     if (FAILED(hr)) {
>-	softTexture->Release();
> 	return (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED;
>     }
>     *image_out = 
> 	(cairo_image_surface_t*)_cairo_image_surface_create_for_data_with_content((unsigned char*)data.pData,
> 										  CAIRO_CONTENT_COLOR_ALPHA,
> 										  size.width,
> 										  size.height,
> 										  data.RowPitch);
>-    *image_extra = softTexture;
>+    *image_extra = softTexture.forget();
> 
>     return CAIRO_STATUS_SUCCESS;
> }
> 
> static void
> _cairo_d2d_release_source_image(void                   *abstract_surface,
> 				cairo_image_surface_t  *image,
> 				void                   *image_extra)
>@@ -1514,25 +1451,24 @@ _cairo_d2d_acquire_dest_image(void      
> 			      void                   **image_extra)
> {
>     cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(abstract_surface);
>     _cairo_d2d_flush(d2dsurf);
> 
>     HRESULT hr;
>     D2D1_SIZE_U size = d2dsurf->rt->GetPixelSize();
> 
>-    ID3D10Texture2D *softTexture;
>+    RefPtr<ID3D10Texture2D> softTexture;
> 
> 
>-    IDXGISurface *dxgiSurface;
>+    RefPtr<IDXGISurface> dxgiSurface;
>     d2dsurf->surface->QueryInterface(&dxgiSurface);
>     DXGI_SURFACE_DESC desc;
> 
>     dxgiSurface->GetDesc(&desc);
>-    dxgiSurface->Release();
> 
>     CD3D10_TEXTURE2D_DESC softDesc(desc.Format, desc.Width, desc.Height);
> 
>     image_rect->width = desc.Width;
>     image_rect->height = desc.Height;
>     image_rect->x = image_rect->y = 0;
> 
>     softDesc.MipLevels = 1;
>@@ -1543,26 +1479,25 @@ _cairo_d2d_acquire_dest_image(void      
>     if (FAILED(hr)) {
> 	return CAIRO_STATUS_NO_MEMORY;
>     }
>     D3D10Factory::Device()->CopyResource(softTexture, d2dsurf->surface);
> 
>     D3D10_MAPPED_TEXTURE2D data;
>     hr = softTexture->Map(0, D3D10_MAP_READ_WRITE, 0, &data);
>     if (FAILED(hr)) {
>-	softTexture->Release();
> 	return (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED;
>     }
>     *image_out = 
> 	(cairo_image_surface_t*)_cairo_image_surface_create_for_data_with_content((unsigned char*)data.pData,
> 										  CAIRO_CONTENT_COLOR_ALPHA,
> 										  size.width,
> 										  size.height,
> 										  data.RowPitch);
>-    *image_extra = softTexture;
>+    *image_extra = softTexture.forget();
> 
>     return CAIRO_STATUS_SUCCESS;
> }
> 
> static void
> _cairo_d2d_release_dest_image(void                    *abstract_surface,
> 			      cairo_rectangle_int_t   *interest_rect,
> 			      cairo_image_surface_t   *image,
>@@ -1593,17 +1528,16 @@ _cairo_d2d_intersect_clip_path(void			*d
> 			       double			tolerance,
> 			       cairo_antialias_t	antialias)
> {
>     cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(dst);
> 
>     _cairo_d2d_surface_pop_clip(d2dsurf);
>     if (!path) {
> 	if (d2dsurf->clipMask) {
>-	    d2dsurf->clipMask->Release();
> 	    d2dsurf->clipMask = NULL;
> 	}
> 	if (d2dsurf->clipRect) {
> 	    delete d2dsurf->clipRect;
> 	    d2dsurf->clipRect = NULL;
> 	}
> 	return CAIRO_INT_STATUS_SUCCESS;
>     }
>@@ -1634,89 +1568,77 @@ _cairo_d2d_intersect_clip_path(void			*d
> 		d2dsurf->clipRect->left = d2dsurf->clipRect->right;
> 	    }
> 	    return CAIRO_INT_STATUS_SUCCESS;
> 	} else {
> 	    /** 
> 	     * We have a mask, see if this rect is completely contained by it, so we
> 	     * can optimize by just using this rect rather than a geometry mask.
> 	     */
>-	    ID2D1RectangleGeometry *newMask;
>+	    RefPtr<ID2D1RectangleGeometry> newMask;
> 	    D2DSurfFactory::Instance()->CreateRectangleGeometry(D2D1::RectF(_cairo_fixed_to_float(box.p1.x),
> 									    _cairo_fixed_to_float(box.p1.y),
> 									    _cairo_fixed_to_float(box.p2.x),
> 									    _cairo_fixed_to_float(box.p2.y)), 
> 								&newMask);
> 	    D2D1_GEOMETRY_RELATION relation;
> 	    d2dsurf->clipMask->CompareWithGeometry(newMask, D2D1::Matrix3x2F::Identity(), &relation);
> 	    if (relation == D2D1_GEOMETRY_RELATION_CONTAINS) {
>-	        d2dsurf->clipMask->Release();
> 		d2dsurf->clipMask = NULL;
>-	        newMask->Release();
> 	        d2dsurf->clipRect = new D2D1_RECT_F(D2D1::RectF(_cairo_fixed_to_float(box.p1.x),
> 								_cairo_fixed_to_float(box.p1.y),
> 								_cairo_fixed_to_float(box.p2.x),
> 								_cairo_fixed_to_float(box.p2.y)));
> 		return CAIRO_INT_STATUS_SUCCESS;		    
> 		
> 	    }
>-	    newMask->Release();
> 	}
>     }
>     
>     if (!d2dsurf->clipRect && !d2dsurf->clipMask) {
> 	/** Nothing yet, just use this clip path */
> 	d2dsurf->clipMask = _cairo_d2d_create_path_geometry_for_path(path, fill_rule, D2D1_FIGURE_BEGIN_FILLED);
>     } else if (d2dsurf->clipMask) {
> 	/** We already have a clip mask, combine the two into a new clip mask */
>-	ID2D1Geometry *newMask = _cairo_d2d_create_path_geometry_for_path(path, fill_rule, D2D1_FIGURE_BEGIN_FILLED);
>-	ID2D1PathGeometry *finalMask;
>+	RefPtr<ID2D1Geometry> newMask = _cairo_d2d_create_path_geometry_for_path(path, fill_rule, D2D1_FIGURE_BEGIN_FILLED);
>+	RefPtr<ID2D1PathGeometry> finalMask;
> 	D2DSurfFactory::Instance()->CreatePathGeometry(&finalMask);
>-	ID2D1GeometrySink *sink;
>+	RefPtr<ID2D1GeometrySink> sink;
> 	finalMask->Open(&sink);
> 	newMask->CombineWithGeometry(d2dsurf->clipMask,
> 				     D2D1_COMBINE_MODE_INTERSECT,
> 				     D2D1::Matrix3x2F::Identity(),
> 				     sink);
> 	sink->Close();
>-	sink->Release();
>-	d2dsurf->clipMask->Release();
>-	newMask->Release();
> 	d2dsurf->clipMask = finalMask;
>     } else if (d2dsurf->clipRect) {
> 	/** 
> 	 * We have a clip rect, if we contain it, we can keep using that, if
> 	 * it contains the new path, use the new path, otherwise, go into a
> 	 * potentially expensive combine.
> 	 */
>-	ID2D1RectangleGeometry *currentMask;
>+	RefPtr<ID2D1RectangleGeometry> currentMask;
> 	D2DSurfFactory::Instance()->CreateRectangleGeometry(d2dsurf->clipRect, &currentMask);
>-	ID2D1Geometry *newMask = _cairo_d2d_create_path_geometry_for_path(path, fill_rule, D2D1_FIGURE_BEGIN_FILLED);
>+	RefPtr<ID2D1Geometry> newMask = _cairo_d2d_create_path_geometry_for_path(path, fill_rule, D2D1_FIGURE_BEGIN_FILLED);
>         D2D1_GEOMETRY_RELATION relation;
> 	newMask->CompareWithGeometry(currentMask, D2D1::Matrix3x2F::Identity(), &relation);
> 	if (relation == D2D1_GEOMETRY_RELATION_CONTAINS) {
>-	    currentMask->Release();
>-	    newMask->Release();
> 	    return CAIRO_INT_STATUS_SUCCESS;
> 	} else if (relation == D2D1_GEOMETRY_RELATION_IS_CONTAINED) {
>-	    currentMask->Release();
> 	    d2dsurf->clipMask = newMask;
> 	} else {
>-	    ID2D1PathGeometry *finalMask;
>+	    RefPtr<ID2D1PathGeometry> finalMask;
> 	    D2DSurfFactory::Instance()->CreatePathGeometry(&finalMask);
>-	    ID2D1GeometrySink *sink;
>+	    RefPtr<ID2D1GeometrySink> sink;
> 	    finalMask->Open(&sink);
> 	    newMask->CombineWithGeometry(currentMask,
> 					 D2D1_COMBINE_MODE_INTERSECT,
> 					 D2D1::Matrix3x2F::Identity(),
> 					 sink);
> 	    sink->Close();
>-	    sink->Release();
>-	    currentMask->Release();
>-	    newMask->Release();
> 	    d2dsurf->clipMask = finalMask;
> 	}
>     }
> 
>     if (d2dsurf->clipRect) {
> 	delete d2dsurf->clipRect;
> 	d2dsurf->clipRect = NULL;
>     }
>@@ -1755,21 +1677,21 @@ _cairo_d2d_paint(void			*surface,
> 
>     d2dsurf->rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
> 
>     unsigned int runs_remaining = 1;
>     unsigned int last_run = 0;
>     bool pushed_clip = false;
> 
>     while (runs_remaining) {
>-	ID2D1Brush *brush = _cairo_d2d_create_brush_for_pattern(d2dsurf,
>-								source,
>-								last_run++,
>-								&runs_remaining,
>-								&pushed_clip);
>+	RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf,
>+								       source,
>+								       last_run++,
>+								       &runs_remaining,
>+								       &pushed_clip);
> 
> 	if (!brush) {
> 	    return CAIRO_INT_STATUS_UNSUPPORTED;
> 	}
> 	if (op == CAIRO_OPERATOR_OVER && extents) {
> 	    d2dsurf->rt->FillRectangle(D2D1::RectF((FLOAT)extents->x,
> 						   (FLOAT)extents->y,
> 						   (FLOAT)extents->x + extents->width,
>@@ -1786,20 +1708,18 @@ _cairo_d2d_paint(void			*surface,
> 	    D2D1_SIZE_F size = d2dsurf->rt->GetSize();
>             d2dsurf->rt->Clear(D2D1::ColorF(0, 0));
>             d2dsurf->rt->FillRectangle(D2D1::RectF((FLOAT)0,
> 						   (FLOAT)0,
> 						   (FLOAT)size.width,
> 						   (FLOAT)size.height),
> 				       brush);
>         } else {
>-	    brush->Release();
> 	    return CAIRO_INT_STATUS_UNSUPPORTED;
> 	}
>-	brush->Release();
> 
> 	if (pushed_clip) {
> 	    d2dsurf->rt->PopLayer();
> 	}
>     }
>     return CAIRO_INT_STATUS_SUCCESS;
> }
> 
>@@ -1811,22 +1731,21 @@ _cairo_d2d_mask(void			*surface,
> 		cairo_rectangle_int_t	*extents)
> {
>     cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
>     _begin_draw_state(d2dsurf);
> 
>     unsigned int runs_remaining = 0;
>     bool pushed_clip;
> 
>-    ID2D1Brush *brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, source, 0, &runs_remaining, &pushed_clip);
>+    RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf, source, 0, &runs_remaining, &pushed_clip);
>     if (!brush) {
> 	return CAIRO_INT_STATUS_UNSUPPORTED;
>     }
>     if (runs_remaining) {
>-	brush->Release();
> 	// TODO: Implement me!!
> 	return CAIRO_INT_STATUS_UNSUPPORTED;
>     }
>     D2D1_RECT_F rect = D2D1::RectF(0,
> 				   0,
> 				   (FLOAT)d2dsurf->rt->GetPixelSize().width,
> 				   (FLOAT)d2dsurf->rt->GetPixelSize().height);
>     if (extents) {
>@@ -1839,46 +1758,40 @@ _cairo_d2d_mask(void			*surface,
>     if (mask->type == CAIRO_PATTERN_TYPE_SOLID) {
> 	cairo_solid_pattern_t *solidPattern =
> 	    (cairo_solid_pattern_t*)mask;
> 	if (solidPattern->content = CAIRO_CONTENT_ALPHA) {
> 	    brush->SetOpacity((FLOAT)solidPattern->color.alpha);
> 	    d2dsurf->rt->FillRectangle(rect,
> 				       brush);
> 	    brush->SetOpacity(1.0);
>-	    brush->Release();
> 	    return CAIRO_INT_STATUS_SUCCESS;
> 	}
>     }
>-    ID2D1Brush *opacityBrush = _cairo_d2d_create_brush_for_pattern(d2dsurf, mask, 0, &runs_remaining, &pushed_clip, true);
>+    RefPtr<ID2D1Brush> opacityBrush = _cairo_d2d_create_brush_for_pattern(d2dsurf, mask, 0, &runs_remaining, &pushed_clip, true);
>     if (!opacityBrush) {
>-	brush->Release();
> 	return CAIRO_INT_STATUS_UNSUPPORTED;
>     }
>     if (runs_remaining) {
>-	brush->Release();
>-	opacityBrush->Release();
> 	return CAIRO_INT_STATUS_UNSUPPORTED;
>     }
>     if (!d2dsurf->maskLayer) {
> 	d2dsurf->rt->CreateLayer(&d2dsurf->maskLayer);
>     }
>     d2dsurf->rt->PushLayer(D2D1::LayerParameters(D2D1::InfiniteRect(),
> 						 0,
> 						 D2D1_ANTIALIAS_MODE_ALIASED,
> 						 D2D1::IdentityMatrix(),
> 						 1.0,
> 						 opacityBrush),
> 			   d2dsurf->maskLayer);
> 
>     d2dsurf->rt->FillRectangle(rect,
> 			       brush);
>     d2dsurf->rt->PopLayer();
>-    brush->Release();
>-    opacityBrush->Release();
>     return CAIRO_INT_STATUS_SUCCESS;
> }
> 
> static cairo_int_status_t
> _cairo_d2d_stroke(void			*surface,
> 		  cairo_operator_t	 op,
> 		  const cairo_pattern_t	*source,
> 		  cairo_path_fixed_t	*path,
>@@ -1904,112 +1817,101 @@ _cairo_d2d_stroke(void			*surface,
> 	return CAIRO_INT_STATUS_UNSUPPORTED;
>     }
> 
>     if (antialias == CAIRO_ANTIALIAS_NONE) {
> 	d2dsurf->rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
>     } else {
> 	d2dsurf->rt->SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
>     }
>-    ID2D1StrokeStyle *strokeStyle = _cairo_d2d_create_strokestyle_for_stroke_style(style);
>+    RefPtr<ID2D1StrokeStyle> strokeStyle = _cairo_d2d_create_strokestyle_for_stroke_style(style);
> 
>     if (!strokeStyle) {
> 	return CAIRO_INT_STATUS_UNSUPPORTED;
>     }
>     D2D1::Matrix3x2F mat = _cairo_d2d_matrix_from_matrix(ctm);
> 
>     _cairo_path_fixed_transform(path, ctm_inverse);
> 
>     if (op == CAIRO_OPERATOR_CLEAR) {
>-	ID2D1Geometry *d2dpath = _cairo_d2d_create_path_geometry_for_path(path,
>-									  CAIRO_FILL_RULE_WINDING,
>-									  D2D1_FIGURE_BEGIN_FILLED);
>+	RefPtr<ID2D1Geometry> d2dpath = _cairo_d2d_create_path_geometry_for_path(path,
>+										 CAIRO_FILL_RULE_WINDING,
>+										 D2D1_FIGURE_BEGIN_FILLED);
> 
>         ID2D1PathGeometry *strokeGeometry;
> 	D2DSurfFactory::Instance()->CreatePathGeometry(&strokeGeometry);
> 
>-	ID2D1GeometrySink *sink;
>+	RefPtr<ID2D1GeometrySink> sink;
> 	strokeGeometry->Open(&sink);
> 	d2dpath->Widen((FLOAT)style->line_width, strokeStyle, mat, (FLOAT)tolerance, sink);
> 	sink->Close();
>-	sink->Release();
> 
> 	_cairo_d2d_clear_geometry(d2dsurf, strokeGeometry);
> 
>-	strokeGeometry->Release();
>-	d2dpath->Release();
>-
>-        return CAIRO_INT_STATUS_SUCCESS;
>+	return CAIRO_INT_STATUS_SUCCESS;
>     }
> 
>     d2dsurf->rt->SetTransform(mat);
> 
>     unsigned int runs_remaining = 1;
>     unsigned int last_run = 0;
>     bool pushed_clip = false;
>     cairo_box_t box;
> 
>     if (_cairo_path_fixed_is_box(path, &box)) {
> 	float x1 = _cairo_fixed_to_float(box.p1.x);    
> 	float y1 = _cairo_fixed_to_float(box.p1.y);    
> 	float x2 = _cairo_fixed_to_float(box.p2.x);    
> 	float y2 = _cairo_fixed_to_float(box.p2.y);
> 	while (runs_remaining) {
>-	    ID2D1Brush *brush = _cairo_d2d_create_brush_for_pattern(d2dsurf,
>-								    source,
>-								    last_run++,
>-								    &runs_remaining,
>-								    &pushed_clip);
>+	    RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf,
>+			    						   source,
>+									   last_run++,
>+									   &runs_remaining,
>+									   &pushed_clip);
> 
> 	    if (!brush) {
>-		strokeStyle->Release();
> 		return CAIRO_INT_STATUS_UNSUPPORTED;
> 	    }
> 	    d2dsurf->rt->DrawRectangle(D2D1::RectF(x1,
> 						   y1,
> 						   x2,
> 						   y2),
> 				       brush,
> 				       (FLOAT)style->line_width,
> 				       strokeStyle);
> 
>-	    brush->Release();
> 	    if (pushed_clip) {
> 		d2dsurf->rt->PopLayer();
> 	    }
> 	}
>     } else {
>-	ID2D1Geometry *d2dpath = _cairo_d2d_create_path_geometry_for_path(path, 
>-									  CAIRO_FILL_RULE_WINDING, 
>-									  D2D1_FIGURE_BEGIN_HOLLOW);
>+	RefPtr<ID2D1Geometry> d2dpath = _cairo_d2d_create_path_geometry_for_path(path, 
>+			    							 CAIRO_FILL_RULE_WINDING, 
>+										 D2D1_FIGURE_BEGIN_HOLLOW);
> 	while (runs_remaining) {
>-	    ID2D1Brush *brush = _cairo_d2d_create_brush_for_pattern(d2dsurf,
>-								    source,
>-								    last_run++,
>-								    &runs_remaining,
>-								    &pushed_clip);
>+	    RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf,
>+									   source,
>+									   last_run++,
>+									   &runs_remaining,
>+									   &pushed_clip);
> 
> 	    if (!brush) {
>-		strokeStyle->Release();
>-		d2dpath->Release();
> 		return CAIRO_INT_STATUS_UNSUPPORTED;
> 	    }
> 	    d2dsurf->rt->DrawGeometry(d2dpath, brush, (FLOAT)style->line_width, strokeStyle);
> 
>-	    brush->Release();
> 	    if (pushed_clip) {
> 		d2dsurf->rt->PopLayer();
> 	    }
> 	}
>-	d2dpath->Release();
>     }
> 
>     _cairo_path_fixed_transform(path, ctm);
>     d2dsurf->rt->SetTransform(D2D1::Matrix3x2F::Identity());
>-    strokeStyle->Release();
>     return CAIRO_INT_STATUS_SUCCESS;
> }
> 
> static cairo_int_status_t
> _cairo_d2d_fill(void			*surface,
> 		cairo_operator_t	 op,
> 		const cairo_pattern_t	*source,
> 		cairo_path_fixed_t	*path,
>@@ -2054,69 +1956,64 @@ _cairo_d2d_fill(void			*surface,
> 							 _cairo_fixed_to_float(box.p1.y),
> 							 _cairo_fixed_to_float(box.p2.x),
> 							 _cairo_fixed_to_float(box.p2.y)),
> 					     D2D1_ANTIALIAS_MODE_PER_PRIMITIVE);
> 	    d2dsurf->rt->Clear(D2D1::ColorF(0, 0));
> 	    d2dsurf->rt->PopAxisAlignedClip();
> 	    return CAIRO_INT_STATUS_SUCCESS;
> 	}
>-	ID2D1Geometry *d2dpath = _cairo_d2d_create_path_geometry_for_path(path,
>-									  fill_rule,
>-									  D2D1_FIGURE_BEGIN_FILLED);
>+	RefPtr<ID2D1Geometry> d2dpath = _cairo_d2d_create_path_geometry_for_path(path,
>+										 fill_rule,
>+										 D2D1_FIGURE_BEGIN_FILLED);
> 	_cairo_d2d_clear_geometry(d2dsurf, d2dpath);
> 	
>-	d2dpath->Release();
> 	return CAIRO_INT_STATUS_SUCCESS;
>     }
> 
>     if (_cairo_path_fixed_is_box(path, &box)) {
> 	float x1 = _cairo_fixed_to_float(box.p1.x);
> 	float y1 = _cairo_fixed_to_float(box.p1.y);    
> 	float x2 = _cairo_fixed_to_float(box.p2.x);    
> 	float y2 = _cairo_fixed_to_float(box.p2.y);
> 	while (runs_remaining) {
>-	    ID2D1Brush *brush = _cairo_d2d_create_brush_for_pattern(d2dsurf,
>-								    source,
>-								    last_run++,
>-								    &runs_remaining,
>-								    &pushed_clip);
>+	    RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf,
>+									   source,
>+									   last_run++,
>+									   &runs_remaining,
>+									   &pushed_clip);
> 	    if (!brush) {
> 		return CAIRO_INT_STATUS_UNSUPPORTED;
> 	    }
> 
> 	    d2dsurf->rt->FillRectangle(D2D1::RectF(x1,
> 						   y1,
> 						   x2,
> 						   y2),
> 				       brush);
> 	    if (pushed_clip) {
> 		d2dsurf->rt->PopLayer();
> 	    }
>-	    brush->Release();
> 	}
>     } else {
>-	ID2D1Geometry *d2dpath = _cairo_d2d_create_path_geometry_for_path(path, fill_rule, D2D1_FIGURE_BEGIN_FILLED);
>+	RefPtr<ID2D1Geometry> d2dpath = _cairo_d2d_create_path_geometry_for_path(path, fill_rule, D2D1_FIGURE_BEGIN_FILLED);
> 	while (runs_remaining) {
>-	    ID2D1Brush *brush = _cairo_d2d_create_brush_for_pattern(d2dsurf,
>-								    source,
>-								    last_run++,
>-								    &runs_remaining,
>-								    &pushed_clip);
>+	    RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(d2dsurf,
>+									   source,
>+									   last_run++,
>+									   &runs_remaining,
>+									   &pushed_clip);
> 	    if (!brush) {
>-		d2dpath->Release();
> 		return CAIRO_INT_STATUS_UNSUPPORTED;
> 	    }
> 	    d2dsurf->rt->FillGeometry(d2dpath, brush);
>-	    brush->Release();
> 	    if (pushed_clip) {
> 		d2dsurf->rt->PopLayer();
> 	    }
> 	}
>-	d2dpath->Release();
>     }
>     return CAIRO_INT_STATUS_SUCCESS;
> }
> 
> static cairo_int_status_t
> _cairo_d2d_show_glyphs (void			*surface,
> 			cairo_operator_t	 op,
> 			const cairo_pattern_t	*source,
>@@ -2126,21 +2023,20 @@ _cairo_d2d_show_glyphs (void			*surface,
> 			int			*remaining_glyphs,
> 			cairo_rectangle_int_t	*extents)
> {
>     if (((cairo_surface_t*)surface)->type != CAIRO_SURFACE_TYPE_D2D) {
> 	return CAIRO_INT_STATUS_UNSUPPORTED;
>     }
>     cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
>     if (!d2dsurf->textRenderingInit) {
>-	IDWriteRenderingParams *params;
>+	RefPtr<IDWriteRenderingParams> params;
> 	DWriteFactory::Instance()->CreateRenderingParams(&params);
> 	d2dsurf->rt->SetTextRenderingParams(params);
> 	d2dsurf->textRenderingInit = true;
>-	params->Release();
>     }
>     _begin_draw_state(d2dsurf);
>     cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
>     if (scaled_font->backend->type == CAIRO_FONT_TYPE_DWRITE) {
>         status = (cairo_int_status_t)
> 	    cairo_dwrite_show_glyphs_on_d2d_surface(surface, op, source, glyphs, num_glyphs, scaled_font, extents);
>     }
> 
>@@ -2173,18 +2069,18 @@ cairo_d2d_surface_create_for_hwnd(HWND w
> 	/**
> 	 * FIXME: In the near future we can use cairo_device_t to pass in a
> 	 * device.
> 	 */
> 	return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_DEVICE));
>     }
> 
>     cairo_d2d_surface_t *newSurf = static_cast<cairo_d2d_surface_t*>(malloc(sizeof(cairo_d2d_surface_t)));
>+    new (newSurf) cairo_d2d_surface_t();
> 
>-    memset(newSurf, 0, sizeof(cairo_d2d_surface_t));
>     _cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, CAIRO_CONTENT_COLOR);
> 
>     RECT rc;
>     HRESULT hr;
> 
>     newSurf->isDrawing = false;
>     ::GetClientRect(wnd, &rc);
> 
>@@ -2202,25 +2098,26 @@ cairo_d2d_surface_create_for_hwnd(HWND w
> 
>     if (!sizePixels.width) {
> 	sizePixels.width = 1;
>     }
>     if (!sizePixels.height) {
> 	sizePixels.height = 1;
>     }
>     ID3D10Device1 *device = D3D10Factory::Device();
>-    IDXGIDevice *dxgiDevice;
>-    IDXGIAdapter *dxgiAdapter;
>-    IDXGIFactory *dxgiFactory;
>-    
>+    RefPtr<IDXGIDevice> dxgiDevice;
>+    RefPtr<IDXGIAdapter> dxgiAdapter;
>+    RefPtr<IDXGIFactory> dxgiFactory;
>+    RefPtr<IDXGISurface> dxgiSurface;
>+    D2D1_RENDER_TARGET_PROPERTIES props;    
>+    D2D1_BITMAP_PROPERTIES bitProps;
>+
>     device->QueryInterface(&dxgiDevice);
>     dxgiDevice->GetAdapter(&dxgiAdapter);
>     dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory));
>-    dxgiAdapter->Release();
>-    dxgiDevice->Release();
> 
>     DXGI_SWAP_CHAIN_DESC swapDesc;
>     ::ZeroMemory(&swapDesc, sizeof(swapDesc));
> 
>     swapDesc.BufferDesc.Width = sizePixels.width;
>     swapDesc.BufferDesc.Height = sizePixels.height;
>     swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
>     swapDesc.BufferDesc.RefreshRate.Numerator = 60;
>@@ -2234,82 +2131,75 @@ cairo_d2d_surface_create_for_hwnd(HWND w
> 
>     /**
>      * Create a swap chain, this swap chain will contain the backbuffer for
>      * the window we draw to. The front buffer is the full screen front
>      * buffer.
>      */
>     hr = dxgiFactory->CreateSwapChain(dxgiDevice, &swapDesc, &newSurf->dxgiChain);
> 
>-    dxgiFactory->Release();
>     if (FAILED(hr)) {
>-	free(newSurf);
>-	return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
>+	goto FAIL_HWND;
>     }
>     /** Get the backbuffer surface from the swap chain */
>     hr = newSurf->dxgiChain->GetBuffer(0,
> 	                               IID_PPV_ARGS(&newSurf->backBuf));
> 
>     if (FAILED(hr)) {
>-	newSurf->dxgiChain->Release();
>-	free(newSurf);
>-	return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
>+	goto FAIL_HWND;
>     }
> 
>     newSurf->backBuf->QueryInterface(&newSurf->surface);
> 
>     size.width = sizePixels.width * dpiX;
>     size.height = sizePixels.height * dpiY;
> 
>     /** Create the DXGI surface. */
>-    IDXGISurface *dxgiSurface;
>     hr = newSurf->surface->QueryInterface(IID_IDXGISurface, (void**)&dxgiSurface);
> 
>-    D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT,
>+    props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT,
> 								       D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED),
> 								       dpiX,
> 								       dpiY,
> 								       D2D1_RENDER_TARGET_USAGE_NONE);
>     hr = D2DSurfFactory::Instance()->CreateDxgiSurfaceRenderTarget(dxgiSurface,
> 								   props,
> 								   &newSurf->rt);
>     if (FAILED(hr)) {
>-	dxgiSurface->Release();
>-	newSurf->surface->Release();
>-	newSurf->dxgiChain->Release();
>-	newSurf->backBuf->Release();
>-	free(newSurf);
>-	return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
>+	goto FAIL_HWND;
>     }
> 
>-    D2D1_BITMAP_PROPERTIES bitProps = D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, 
>+    bitProps = D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, 
> 									       D2D1_ALPHA_MODE_PREMULTIPLIED));
>     
>-    dxgiSurface->Release();
>-
>     newSurf->rt->CreateSolidColorBrush(D2D1::ColorF(0, 1.0), &newSurf->solidColorBrush);
> 
>     return reinterpret_cast<cairo_surface_t*>(newSurf);
>+
>+FAIL_HWND:
>+    newSurf->~cairo_d2d_surface_t();
>+    free(newSurf);
>+    return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
> }
> 
> cairo_surface_t *
> cairo_d2d_surface_create(cairo_format_t format,
>                          int width,
>                          int height)
> {
>     if (!D3D10Factory::Device() || !D2DSurfFactory::Instance()) {
> 	/**
> 	 * FIXME: In the near future we can use cairo_device_t to pass in a
> 	 * device.
> 	 */
> 	return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_DEVICE));
>     }
>     cairo_d2d_surface_t *newSurf = static_cast<cairo_d2d_surface_t*>(malloc(sizeof(cairo_d2d_surface_t)));
>+    new (newSurf) cairo_d2d_surface_t();
> 
>-    memset(newSurf, 0, sizeof(cairo_d2d_surface_t));
>     DXGI_FORMAT dxgiformat = DXGI_FORMAT_B8G8R8A8_UNORM;
>     D2D1_ALPHA_MODE alpha = D2D1_ALPHA_MODE_PREMULTIPLIED;
>     if (format == CAIRO_FORMAT_ARGB32) {
> 	_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, CAIRO_CONTENT_COLOR_ALPHA);
>     } else if (format == CAIRO_FORMAT_RGB24) {
> 	_cairo_surface_init(&newSurf->base, &cairo_d2d_surface_backend, CAIRO_CONTENT_COLOR);
> 	alpha = D2D1_ALPHA_MODE_IGNORE;
>     } else {
>@@ -2328,90 +2218,83 @@ cairo_d2d_surface_create(cairo_format_t 
> 	dxgiformat,
> 	sizePixels.width,
> 	sizePixels.height
> 	);
>     desc.MipLevels = 1;
>     desc.Usage = D3D10_USAGE_DEFAULT;
>     desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
>     
>-    ID3D10Texture2D *texture;
>+    RefPtr<ID3D10Texture2D> texture;
>+    RefPtr<IDXGISurface> dxgiSurface;
>+    D2D1_BITMAP_PROPERTIES bitProps;
>+    D2D1_RENDER_TARGET_PROPERTIES props;
> 
>     hr = D3D10Factory::Device()->CreateTexture2D(&desc, NULL, &texture);
> 
>     if (FAILED(hr)) {
>-	free(newSurf);
>-	return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
>+	goto FAIL_CREATE;
>     }
> 
>     newSurf->surface = texture;
> 
>     /** Create the DXGI surface. */
>-    IDXGISurface *dxgiSurface;
>     hr = newSurf->surface->QueryInterface(IID_IDXGISurface, (void**)&dxgiSurface);
>     if (FAILED(hr)) {
>-	newSurf->surface->Release();
>-	free(newSurf);
>-	return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
>+	goto FAIL_CREATE;
>     }
> 
>-    D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT,
>+    props = D2D1::RenderTargetProperties(D2D1_RENDER_TARGET_TYPE_DEFAULT,
> 								       D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, alpha));
>     hr = D2DSurfFactory::Instance()->CreateDxgiSurfaceRenderTarget(dxgiSurface,
> 								   props,
> 								   &newSurf->rt);
> 
>     if (FAILED(hr)) {
>-	dxgiSurface->Release();
>-	newSurf->surface->Release();
>-	free(newSurf);
>-	return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
>+	goto FAIL_CREATE;
>     }
> 
>-    D2D1_BITMAP_PROPERTIES bitProps = D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, 
>+    bitProps = D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, 
> 									       alpha));
>     hr = newSurf->rt->CreateSharedBitmap(IID_IDXGISurface,
> 					 dxgiSurface,
> 					 &bitProps,
> 					 &newSurf->surfaceBitmap);
> 
>     if (FAILED(hr)) {
>-	dxgiSurface->Release();
>-	newSurf->rt->Release();
>-	newSurf->surface->Release();
>-	free(newSurf);
>-	return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
>     }
> 
>-    dxgiSurface->Release();
>-
>     newSurf->rt->CreateSolidColorBrush(D2D1::ColorF(0, 1.0), &newSurf->solidColorBrush);
> 
>     return reinterpret_cast<cairo_surface_t*>(newSurf);
>+
>+FAIL_CREATE:
>+    newSurf->~cairo_d2d_surface_t();
>+    free(newSurf);
>+    return _cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY));
> }
> 
> void cairo_d2d_scroll(cairo_surface_t *surface, int x, int y, cairo_rectangle_t *clip)
> {
>     if (surface->type != CAIRO_SURFACE_TYPE_D2D) {
>         return;
>     }
>     cairo_d2d_surface_t *d2dsurf = reinterpret_cast<cairo_d2d_surface_t*>(surface);
> 
>     /** For now, we invalidate our storing texture with this operation. */
>     D2D1_POINT_2U point;
>     D3D10_BOX rect;
>     rect.front = 0;
>     rect.back = 1;
> 
>-    IDXGISurface *dxgiSurface;
>+    RefPtr<IDXGISurface> dxgiSurface;
>     d2dsurf->surface->QueryInterface(&dxgiSurface);
>     DXGI_SURFACE_DESC desc;
> 
>     dxgiSurface->GetDesc(&desc);
>-    dxgiSurface->Release();
> 
>     /**
>      * It's important we constrain the size of the clip region to the area of
>      * the surface. If we don't we might get a box that goes outside the
>      * surface, and CopySubresourceRegion will become very angry with us.
>      * It will cause a device failure and subsequent drawing will break.
>      */
>     clip->x = MAX(clip->x, 0);
>diff --git a/gfx/cairo/cairo/src/cairo-dwrite-font.cpp b/gfx/cairo/cairo/src/cairo-dwrite-font.cpp
>--- a/gfx/cairo/cairo/src/cairo-dwrite-font.cpp
>+++ b/gfx/cairo/cairo/src/cairo-dwrite-font.cpp
>@@ -1317,21 +1317,21 @@ cairo_dwrite_show_glyphs_on_d2d_surface(
>     if (transform) {
> 	dst->rt->SetTransform(mat);
>     }
>     unsigned int last_run = 0;
>     unsigned int runs_remaining = 1;
>     bool pushed_clip = false;
> 
>     while (runs_remaining) {
>-	ID2D1Brush *brush = _cairo_d2d_create_brush_for_pattern(dst,
>-								source,
>-								last_run++,
>-								&runs_remaining,
>-								&pushed_clip);
>+	RefPtr<ID2D1Brush> brush = _cairo_d2d_create_brush_for_pattern(dst,
>+								       source,
>+								       last_run++,
>+								       &runs_remaining,
>+								       &pushed_clip);
> 	if (!brush) {
> 	    delete [] indices;
> 	    delete [] offsets;
> 	    delete [] advances;
> 	    return CAIRO_INT_STATUS_UNSUPPORTED;
> 	}
> 	if (transform) {
> 	    D2D1::Matrix3x2F mat_inverse = _cairo_d2d_matrix_from_matrix(&dwritesf->mat_inverse);
>@@ -1340,17 +1340,16 @@ cairo_dwrite_show_glyphs_on_d2d_surface(
> 	    // The brush matrix needs to be multiplied with the inverted matrix
> 	    // as well, to move the brush into the space of the glyphs. Before
> 	    // the render target transformation.
> 	    brush->GetTransform(&mat_brush);
> 	    mat_brush = mat_brush * mat_inverse;
> 	    brush->SetTransform(&mat_brush);
> 	}
>         dst->rt->DrawGlyphRun(D2D1::Point2F(0, 0), &run, brush);
>-	brush->Release();
> 	if (pushed_clip) {
> 	    dst->rt->PopLayer();
> 	}
>     }
>     if (transform) {
> 	dst->rt->SetTransform(D2D1::Matrix3x2F::Identity());
>     }
Attachment #433773 - Flags: review?(jmuizelaar) → review+
Comment on attachment 433773 [details] [diff] [review]
Part 2: Use RefPtr class in cairo-d2d-surface v2

I forgot to trim the last comment. Here's the trimmed version.

>  */
> static void _d2d_release_bitmap(void *bitmap)
> {
>     cached_bitmap *bitmp = (cached_bitmap*)bitmap;
>-    bitmp->bitmap->Release();
>     if (!--bitmp->refs) {
> 	delete bitmap;

looks like we're calling delete on the wrong object here, and so we'd leak bitmp->bitmap.
you should probably use better names than bitmap/bitmp.
I'm getting random crashes with today nightly and i think it could be related to this checking , this is the crash report 

http://crash-stats.mozilla.com/report/index/d77b67db-b148-4e13-bee7-2cfe62100410

The browser stops painting anything , i get black tabs in aeropeek preview and it crashes after few seconds. Ignore it if it's not related to this
I found a minor problem with this patch, but I'm not sure if it is worth a new bug.
Part of this patch added the following line:
http://hg.mozilla.org/mozilla-central/file/87be0d140fd6/gfx/cairo/cairo/src/cairo-d2d-private.h#l58
which initializes textRenderingInit to be true.
This then prevents the block of code at
http://hg.mozilla.org/mozilla-central/file/87be0d140fd6/gfx/cairo/cairo/src/cairo-d2d-surface.cpp#l2463
from ever running.
This seems fairly benign as, as far as I can see, calling DWriteFactory::Instance()->CreateRenderingParams just returns the default rendering parameters that dwrite starts with anyway, so this block of code basically does nothing anyway, which is why i guess this wasn't noticed earlier.

I noticed this as I'm running a local patch that modifies both instances of CreateRenderingParams to enable symmetric cleartype anti-aliasing at all font sizes, which was only working for dwrite+gdi and not for dwrite+d2d after this patch.
Only just got around to looking into why recently which revealed this issue.
Status: ASSIGNED → RESOLVED
Closed: 3 years ago
Resolution: --- → FIXED
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: