Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement CachedBitmap functionality #654

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
2 changes: 2 additions & 0 deletions src/GdiPlusFlat.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ extern "C"
typedef void GpAdjustableArrowCap;
typedef void GpBitmap;
typedef void GpBrush;
typedef void GpCachedBitmap;
typedef void GpCustomLineCap;
typedef void GpFont;
typedef void GpFontCollection;
Expand Down Expand Up @@ -87,6 +88,7 @@ typedef void GpTexture;
#include "adjustablearrowcap.h"
#include "bitmap.h"
#include "brush.h"
#include "cachedbitmap.h"
#include "customlinecap.h"
#include "font.h"
#include "fontcollection.h"
Expand Down
3 changes: 3 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ libgdiplus_la_SOURCES = \
brush.c \
brush.h \
brush-private.h \
cachedbitmap.c \
cachedbitmap.h \
cachedbitmap-private.h \
carbon-private.c \
carbon-private.h \
codecs.h \
Expand Down
10 changes: 10 additions & 0 deletions src/cachedbitmap-private.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifndef __CACHEDBITMAP_PRIVATE_H__
#define __CACHEDBITMAP_PRIVATE_H__

typedef struct _CachedBitmap {
cairo_surface_t *surface;
} CachedBitmap;

#include "cachedbitmap.h"

#endif
56 changes: 56 additions & 0 deletions src/cachedbitmap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#include "general-private.h"
#include "bitmap-private.h"
#include "graphics-private.h"
#include "cachedbitmap-private.h"

GpStatus WINGDIPAPI
GdipCreateCachedBitmap (GpBitmap *bitmap, GpGraphics *graphics, GpCachedBitmap **cachedBitmap)
{
cairo_t *ct;
cairo_surface_t *surface;
GpCachedBitmap *newCachedBitmap;
cairo_status_t status;

if (!bitmap || !graphics || !cachedBitmap)
return InvalidParameter;
if (bitmap->type != ImageTypeBitmap)
return InvalidParameter;

gdip_bitmap_ensure_surface (bitmap);

surface = cairo_surface_create_similar (bitmap->surface, CAIRO_CONTENT_COLOR_ALPHA, bitmap->active_bitmap->width, bitmap->active_bitmap->height);

ct = cairo_create (surface);

cairo_set_source_surface (ct, bitmap->surface, 0, 0);
cairo_paint (ct);

cairo_destroy (ct);

status = cairo_surface_status (surface);
if (status != CAIRO_STATUS_SUCCESS) {
cairo_surface_destroy (surface);
return gdip_get_status (status);
}

newCachedBitmap = GdipAlloc (sizeof (GpCachedBitmap));
if (!newCachedBitmap)
return OutOfMemory;
reflectronic marked this conversation as resolved.
Show resolved Hide resolved

newCachedBitmap->surface = surface;
*cachedBitmap = newCachedBitmap;

return Ok;
}

GpStatus WINGDIPAPI
GdipDeleteCachedBitmap (GpCachedBitmap *cachedBitmap)
{
if (!cachedBitmap)
return InvalidParameter;

cairo_surface_destroy (cachedBitmap->surface);
GdipFree (cachedBitmap);

return Ok;
}
8 changes: 8 additions & 0 deletions src/cachedbitmap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef __CACHEDBITMAP_H__
#define __CACHEDBITMAP_H__

GpStatus WINGDIPAPI GdipCreateCachedBitmap (GpBitmap *bitmap, GpGraphics *graphics, GpCachedBitmap **cachedBitmap);

GpStatus WINGDIPAPI GdipDeleteCachedBitmap (GpCachedBitmap *cachedBitmap);

#endif
1 change: 1 addition & 0 deletions src/gdiplus-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@

typedef struct _AdjustableArrowCap GpAdjustableArrowCap;
typedef struct _Brush GpBrush;
typedef struct _CachedBitmap GpCachedBitmap;
typedef struct _CustomLineCap GpCustomLineCap;
typedef struct _Font GpFont;
typedef struct _FontCollection GpFontCollection;
Expand Down
17 changes: 17 additions & 0 deletions src/graphics.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "brush-private.h"
#include "matrix-private.h"
#include "bitmap-private.h"
#include "cachedbitmap-private.h"
#include "metafile-private.h"

#include <cairo-features.h>
Expand Down Expand Up @@ -1361,6 +1362,22 @@ GdipDrawCurve3I (GpGraphics *graphics, GpPen* pen, GDIPCONST GpPoint *points, IN
return status;
}

GpStatus WINGDIPAPI
GdipDrawCachedBitmap (GpGraphics *graphics, GpCachedBitmap *cachedBitmap, INT x, INT y)
{
if (!graphics || !cachedBitmap)
return InvalidParameter;
if (graphics->state == GraphicsStateBusy)
return ObjectBusy;

cairo_identity_matrix (graphics->ct);

cairo_set_source_surface (graphics->ct, cachedBitmap->surface, x, y);
cairo_paint (graphics->ct);

return Ok;
}

/*
* Fills
*/
Expand Down
2 changes: 2 additions & 0 deletions src/graphics.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ GpStatus WINGDIPAPI GdipFillPieI( GpGraphics *graphics, GpBrush *brush, INT x, I
GpStatus WINGDIPAPI GdipFillRegion (GpGraphics *graphics, GpBrush *brush, GpRegion *region);
GpStatus WINGDIPAPI GdipGraphicsClear (GpGraphics *graphics, ARGB color);

GpStatus WINGDIPAPI GdipDrawCachedBitmap (GpGraphics *graphics, GpCachedBitmap *cachedBitmap, INT x, INT y);

GpStatus WINGDIPAPI GdipGetDpiX( GpGraphics *graphics, REAL *dpi);
GpStatus WINGDIPAPI GdipGetDpiY (GpGraphics *graphics, REAL *dpi);
GpStatus WINGDIPAPI GdipGetNearestColor (GpGraphics *graphics, ARGB *argb);
Expand Down
10 changes: 10 additions & 0 deletions tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ noinst_PROGRAMS = \
testbits \
testbmpcodec \
testbrush \
testcachedbitmap \
testclip \
testcodecs \
testcustomlinecap \
Expand Down Expand Up @@ -91,6 +92,13 @@ testbrush_SOURCES = \
testbrush_DEPENDENCIES = $(TEST_DEPS)
testbrush_LDADD = $(LDADDS)


testcachedbitmap_SOURCES = \
testcachedbitmap.c

testcachedbitmap_DEPENDENCIES = $(TEST_DEPS)
testcachedbitmap_LDADD = $(LDADDS)

testclip_SOURCES = \
testclip.c

Expand Down Expand Up @@ -283,6 +291,7 @@ EXTRA_DIST = \
$(testbits_SOURCES) \
$(testbmpcodec_SOURCES) \
$(testbrush_SOURCES) \
$(testcachedbitmap_SOURCES) \
$(testclip_SOURCES) \
$(test_codecs_SOURCES) \
$(testcustomlinecap_SOURCES) \
Expand Down Expand Up @@ -339,6 +348,7 @@ TESTS = \
testbits \
testbmpcodec \
testbrush \
testcachedbitmap \
testclip \
testcodecs \
testcustomlinecap \
Expand Down
131 changes: 131 additions & 0 deletions tests/testcachedbitmap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#ifdef WIN32
#ifndef __cplusplus
#error Please compile with a C++ compiler.
#endif
#endif

#if defined(USE_WINDOWS_GDIPLUS)
#include <Windows.h>
#include <GdiPlus.h>

#pragma comment(lib, "gdiplus.lib")
#else
#include <GdiPlusFlat.h>
#endif

#if defined(USE_WINDOWS_GDIPLUS)
using namespace Gdiplus;
using namespace DllExports;
#endif

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "testhelpers.h"

#define C(func) assert (func == Ok)
reflectronic marked this conversation as resolved.
Show resolved Hide resolved

static GpGraphics *getImageGraphics (GpImage **image)
{
WCHAR *filePath;
GpGraphics *graphics;

filePath = createWchar ("test.bmp");
C (GdipLoadImageFromFile (filePath, image));

freeWchar (filePath);

C (GdipGetImageGraphicsContext (*image, &graphics), Ok);

return graphics;
}

static GpImage* getImage (const char* fileName)
{
GpStatus status;
WCHAR *wFileName = wcharFromChar (fileName);
GpImage *image;

status = GdipLoadImageFromFile (wFileName, &image);
assertEqualInt (status, Ok);

freeWchar (wFileName);

return image;
}

static void test_roundtrip ()
{
UINT width;
UINT height;
GpBitmap *originalBitmap;
GpBitmap *surface;
GpGraphics *graphics;
GpCachedBitmap *cached;

originalBitmap = getImage ("test.bmp");

C (GdipGetImageWidth (originalBitmap, &width));
C (GdipGetImageHeight (originalBitmap, &height));

C (GdipCreateBitmapFromScan0 (width, height, 0, PixelFormat32bppARGB, 0, &surface));
C (GdipGetImageGraphicsContext (surface, &graphics));

GpRect rect = {
.X = 0,
.Y = 0,
.Width = width,
.Height = height
};

C (GdipSetVisibleClip_linux (graphics, &rect));
C (GdipCreateCachedBitmap (originalBitmap, graphics, &cached));
C (GdipDrawCachedBitmap (graphics, cached, 0, 0));

for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
ARGB drawn, original;

C (GdipBitmapGetPixel (originalBitmap, x, y, &original));
C (GdipBitmapGetPixel (surface, x, y, &drawn));

assertEqualInt (drawn, original);
}
}
}

static void test_create ()
{
GpStatus status;
GpImage *image;
GpGraphics *graphics;
GpCachedBitmap* cachedBitmap;

graphics = getImageGraphics (&image);

C (GdipCreateCachedBitmap(image, graphics, &cachedBitmap));

// Negative tests.
image = getImage ("test.wmf");
assertEqualInt (GdipCreateCachedBitmap(image, graphics, &cachedBitmap), InvalidParameter);

assertEqualInt (GdipCreateCachedBitmap(image, graphics, NULL), InvalidParameter);
assertEqualInt (GdipCreateCachedBitmap(image, NULL, &cachedBitmap), InvalidParameter);
assertEqualInt (GdipCreateCachedBitmap(NULL, graphics, &cachedBitmap), InvalidParameter);

C (GdipDeleteGraphics(graphics));
C (GdipDisposeImage(image));
}

int main (int argc, char**argv)
{
STARTUP;

test_create ();
reflectronic marked this conversation as resolved.
Show resolved Hide resolved
test_roundtrip ();

SHUTDOWN;
return 0;
}