Skip to content

Commit

Permalink
fix memory leak caused by linear graident brush #37
Browse files Browse the repository at this point in the history
  • Loading branch information
jingwood committed Oct 25, 2020
1 parent 7b353fc commit 74036f4
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 17 deletions.
6 changes: 6 additions & 0 deletions src/D2DLibExport/D2DBrush.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,11 @@ namespace unvell.D2DLib
public abstract class D2DBrush : D2DObject
{
internal D2DBrush(HANDLE handle) : base(handle) { }

public override void Dispose()
{
if (this.Handle != IntPtr.Zero) D2D.ReleaseBrush(this.Handle);
this.handle = IntPtr.Zero;
}
}
}
4 changes: 3 additions & 1 deletion src/D2DLibExport/D2DLib.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ public static D2DBitmap CreateBitmapFromGDIBitmap(D2DDevice device, System.Drawi
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
public static extern void FillEllipse(HANDLE context, ref D2DEllipse rect, D2DColor color);

[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
public static extern void FillEllipseWithBrush(HANDLE ctx, ref D2DEllipse ellipse, HANDLE brush);

#endregion // Simple Sharp

Expand Down Expand Up @@ -312,7 +314,7 @@ public static void AddPathBeziers(HANDLE ctx, D2DBezierSegment[] bezierSegments)
UINT gradientStopCount);

[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
public static extern void FillEllipseWithBrush(HANDLE ctx, ref D2DEllipse ellipse, HANDLE brush);
public static extern void ReleaseBrush(HANDLE brushCtx);

#endregion // Brush

Expand Down
53 changes: 47 additions & 6 deletions src/d2dlib/Brush.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,18 @@ HANDLE CreateSolidColorBrush(HANDLE ctx, D2D1_COLOR_F color)
ID2D1SolidColorBrush* brush;
context->renderTarget->CreateSolidColorBrush(color, &brush);

return (HANDLE)brush;
BrushContext* brushContext = new BrushContext();
brushContext->context = context;
brushContext->type = BrushType::BrushType_SolidBrush;
brushContext->brush = brush;

return (HANDLE)brushContext;
}

void SetSolidColorBrushColor(HANDLE brushHandle, D2D1_COLOR_F color)
{
ID2D1SolidColorBrush* brush = reinterpret_cast<ID2D1SolidColorBrush*>(brushHandle);
BrushContext* brushContext = reinterpret_cast<BrushContext*>(brushHandle);
ID2D1SolidColorBrush* brush = reinterpret_cast<ID2D1SolidColorBrush*>(brushContext->brush);
brush->SetColor(color);
}

Expand All @@ -71,14 +77,23 @@ HANDLE CreateLinearGradientBrush(HANDLE ctx, D2D1_POINT_2F startPoint, D2D1_POIN
hr = renderTarget->CreateGradientStopCollection(gradientStops, gradientStopCount, &gradientStopCollection);

ID2D1LinearGradientBrush* brush = NULL;
BrushContext* brushContext = NULL;

if (SUCCEEDED(hr))
{
hr = renderTarget->CreateLinearGradientBrush(
D2D1::LinearGradientBrushProperties(startPoint, endPoint), gradientStopCollection, &brush);

if (SUCCEEDED(hr)) {
brushContext = new BrushContext();
brushContext->context = context;
brushContext->type = BrushType::BrushType_LinearGradientBrush;
brushContext->brush = brush;
brushContext->gradientStops = gradientStopCollection;
}
}

return (HANDLE)brush;
return (HANDLE)brushContext;
}

HANDLE CreateRadialGradientBrush(HANDLE ctx, D2D1_POINT_2F origin, D2D1_POINT_2F offset,
Expand All @@ -94,13 +109,39 @@ HANDLE CreateRadialGradientBrush(HANDLE ctx, D2D1_POINT_2F origin, D2D1_POINT_2F
hr = renderTarget->CreateGradientStopCollection(
gradientStops, gradientStopCount, &gradientStopCollection);

ID2D1RadialGradientBrush* radialGradientBrush = NULL;
ID2D1RadialGradientBrush* brush = NULL;
BrushContext* brushContext = NULL;

if (SUCCEEDED(hr))
{
hr = renderTarget->CreateRadialGradientBrush(D2D1::RadialGradientBrushProperties(
origin, offset, radiusX, radiusY), gradientStopCollection, &radialGradientBrush);
origin, offset, radiusX, radiusY), gradientStopCollection, &brush);

if (SUCCEEDED(hr)) {
brushContext = new BrushContext();
brushContext->context = context;
brushContext->type = BrushType::BrushType_RadialGradientBrush;
brushContext->brush = brush;
brushContext->gradientStops = gradientStopCollection;
}
}

return (HANDLE)brushContext;
}

void ReleaseBrush(HANDLE brushHandle)
{
BrushContext* brushContext = reinterpret_cast<BrushContext*>(brushHandle);

switch (brushContext->type)
{
case BrushType::BrushType_LinearGradientBrush:
case BrushType::BrushType_RadialGradientBrush:
SafeRelease(&brushContext->gradientStops);
break;
}

return (HANDLE)radialGradientBrush;
SafeRelease(&brushContext->brush);

delete brushContext;
}
17 changes: 17 additions & 0 deletions src/d2dlib/Brush.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,21 @@

#include "Context.h"

enum BrushType {
BrushType_SolidBrush,
BrushType_LinearGradientBrush,
BrushType_RadialGradientBrush,
};

struct BrushContext {
D2DContext* context;
ID2D1Brush* brush;
BrushType type;
union {
ID2D1GradientStopCollection* gradientStops = NULL;
};
};

extern "C"
{
D2DLIB_API HANDLE CreateSolidColorBrush(HANDLE ctx, D2D1_COLOR_F color);
Expand All @@ -37,4 +52,6 @@ extern "C"
D2DLIB_API HANDLE CreateRadialGradientBrush(HANDLE ctx, D2D1_POINT_2F origin, D2D1_POINT_2F offset,
FLOAT radiusX, FLOAT radiusY, D2D1_GRADIENT_STOP* gradientStops,
UINT gradientStopCount);

D2DLIB_API void ReleaseBrush(HANDLE brushHandle);
}
20 changes: 14 additions & 6 deletions src/d2dlib/Geometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include "stdafx.h"
#include "Geometry.h"
#include "Brush.h"

typedef struct D2DPathContext
{
Expand Down Expand Up @@ -286,6 +287,11 @@ void DrawPolygonWithBrush(HANDLE ctx, D2D1_POINT_2F* points, UINT count,
ID2D1PathGeometry* path = NULL;
hr = context->factory->CreatePathGeometry(&path);

if (!SUCCEEDED(hr)) {
context->lastErrorCode = hr;
return;
}

ID2D1GeometrySink* sink = NULL;
hr = path->Open(&sink);

Expand All @@ -300,7 +306,8 @@ void DrawPolygonWithBrush(HANDLE ctx, D2D1_POINT_2F* points, UINT count,

ID2D1Brush* brush = NULL;
if (brushHandle != NULL) {
brush = reinterpret_cast<ID2D1Brush*>(brushHandle);
BrushContext* brushContext = reinterpret_cast<BrushContext*>(brushHandle);
brush = brushContext->brush;
renderTarget->FillGeometry(path, brush);
}

Expand Down Expand Up @@ -337,21 +344,22 @@ void DrawPolygonWithBrush(HANDLE ctx, D2D1_POINT_2F* points, UINT count,
void FillPathWithBrush(HANDLE ctx, HANDLE brushHandle)
{
D2DPathContext* pathContext = reinterpret_cast<D2DPathContext*>(ctx);
ID2D1Brush* brush = reinterpret_cast<ID2D1Brush*>(brushHandle);
BrushContext* brushContext = reinterpret_cast<BrushContext*>(brushHandle);
D2DContext* context = pathContext->d2context;

context->renderTarget->FillGeometry(pathContext->path, brush);
context->renderTarget->FillGeometry(pathContext->path, brushContext->brush);
}

void FillGeometryWithBrush(HANDLE ctx, HANDLE geoHandle, _In_ HANDLE brushHandle, _In_opt_ HANDLE opacityBrushHandle)
{
RetrieveContext(ctx);

ID2D1Geometry* geometry = reinterpret_cast<ID2D1Geometry*>(geoHandle);
ID2D1Brush* brush = reinterpret_cast<ID2D1Brush*>(brushHandle);
ID2D1Brush* opacityBrush = reinterpret_cast<ID2D1Brush*>(opacityBrushHandle);
BrushContext* brushContext = reinterpret_cast<BrushContext*>(brushHandle);
BrushContext* opacityBrushContext = reinterpret_cast<BrushContext*>(opacityBrushHandle);

context->renderTarget->FillGeometry(geometry, brush, opacityBrush);
context->renderTarget->FillGeometry(geometry, brushContext->brush,
opacityBrushContext == NULL ? NULL : opacityBrushContext->brush);
}

bool PathFillContainsPoint(HANDLE pathCtx, D2D1_POINT_2F point)
Expand Down
13 changes: 9 additions & 4 deletions src/d2dlib/Simple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "stdafx.h"
#include "Simple.h"
#include "Pen.h"
#include "Brush.h"

void DrawLine(HANDLE ctx, D2D1_POINT_2F start, D2D1_POINT_2F end, D2D1_COLOR_F color,
FLOAT width, D2D1_DASH_STYLE dashStyle)
Expand Down Expand Up @@ -213,7 +214,8 @@ void FillRectangleWithBrush(HANDLE ctx, D2D1_RECT_F* rect, HANDLE brushHandle)
{
RetrieveContext(ctx);

ID2D1Brush* brush = reinterpret_cast<ID2D1Brush*>(brushHandle);
BrushContext* brushContext = reinterpret_cast<BrushContext*>(brushHandle);
ID2D1Brush* brush = reinterpret_cast<ID2D1Brush*>(brushContext->brush);

if (brush != NULL) {
context->renderTarget->FillRectangle(rect, brush);
Expand Down Expand Up @@ -268,7 +270,8 @@ D2DLIB_API void DrawRoundedRectWithBrush(HANDLE ctx, D2D1_ROUNDED_RECT* roundedR
RetrieveContext(ctx);

D2DPen* pen = reinterpret_cast<D2DPen*>(strokePen);
ID2D1Brush* brush = reinterpret_cast<ID2D1Brush*>(fillBrush);
BrushContext* brushContext = reinterpret_cast<BrushContext*>(fillBrush);
ID2D1Brush* brush = reinterpret_cast<ID2D1Brush*>(brushContext->brush);

if (pen != NULL) {
context->renderTarget->DrawRoundedRectangle(roundedRect, pen->brush, strokeWidth, pen->strokeStyle);
Expand Down Expand Up @@ -325,10 +328,12 @@ void FillEllipse(HANDLE handle, D2D1_ELLIPSE* ellipse, D2D1_COLOR_F color)
SafeRelease(&brush);
}

void FillEllipseWithBrush(HANDLE ctx, D2D1_ELLIPSE* ellipse, HANDLE brush_handle)
void FillEllipseWithBrush(HANDLE ctx, D2D1_ELLIPSE* ellipse, HANDLE brushHandle)
{
RetrieveContext(ctx);

ID2D1Brush* brush = reinterpret_cast<ID2D1Brush*>(brush_handle);
BrushContext* brushContext = reinterpret_cast<BrushContext*>(brushHandle);
ID2D1Brush* brush = reinterpret_cast<ID2D1Brush*>(brushContext->brush);

context->renderTarget->FillEllipse(ellipse, brush);
}

0 comments on commit 74036f4

Please sign in to comment.