Skip to content
This repository was archived by the owner on Mar 7, 2025. It is now read-only.

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
59 changes: 59 additions & 0 deletions src/cachedbitmap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#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)
{
cairo_surface_destroy(surface);
return OutOfMemory;
}

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
130 changes: 130 additions & 0 deletions tests/testcachedbitmap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#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)

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

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

freeWchar (filePath);

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

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 ()
{
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 ();
test_roundtrip ();

SHUTDOWN;
return 0;
}