Nikolay Sivov wrote:
Vincent Povirk wrote:
On Fri, Jul 3, 2009 at 10:00 AM, Andrew
Eikum<and...@brightnightgames.com> wrote:
I agree that the behavior of the container IDs doesn't match native.
However, do we really care to duplicate that behavior? I can't see
any
documentation in MSDN that says container IDs must be unique across
either
graphics objects or within a single graphics object.
I can't imagine any application depending on the uniqueness of
container
IDs; if they try to pass a container for graphics1 to graphics2,
nothing
happens, so there's no behavior to depend on. Ditto for invalid or
already-used containers. The only scenario I can think of where the
uniqueness of container IDs would be a dependency would be an
application
error calling EndContainer() with invalid values. I don't know if it's
worth the effort of making a handle table and whatnot to work around an
application glitch that might not even exist.
So, I would argue against the validity of the test you quote. Why
should
the same value not be returned twice?
+1
If an application does need the ID's to be more like Windows, the code
can be changed to account for it. We don't have to match every quirk
of Windows the first time something is implemented.
Exactly. I'm not talking about that. Allocating handle on Begin..() or
Save..() and releasing it on
End...() or Restore...() should be enough. After that we will probably
never want to change that
but for a first time it's necessary I think.
Okay, how about this patch? It creates a list of available IDs and
assigns/releases them as needed. Seems to work fine from my testing.
It also adds some fixes for things Vincent pointed out last night.
Can you guys check if everything is done correctly from a C/Wine
perspective? I notice that the objects in availableGCIDs are never
explicitly freed; can we just let this happen during cleanup as the
program exits?
>From 91a2ba1aa77cdf5d3c2bf7fe55dc78d24bc5bd9b Mon Sep 17 00:00:00 2001
From: Andrew Eikum <and...@brightnightgames.com>
Date: Thu, 2 Jul 2009 18:43:58 -0500
Subject: gdiplus: Implement GdipBeginContainer2 and GdipEndContainer
To: wine-patches <wine-patc...@winehq.org>
Reply-To: wine-devel <wine-devel@winehq.org>
---
dlls/gdiplus/gdiplus_private.h | 2 +
dlls/gdiplus/graphics.c | 189 ++++++++++++++++++++++++++++++++++++++--
include/gdiplusflat.h | 1 +
3 files changed, 186 insertions(+), 6 deletions(-)
diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h
index 95133ca..b6ed8fe 100644
--- a/dlls/gdiplus/gdiplus_private.h
+++ b/dlls/gdiplus/gdiplus_private.h
@@ -29,6 +29,7 @@
#include "objbase.h"
#include "ocidl.h"
+#include "wine/list.h"
#include "gdiplus.h"
@@ -109,6 +110,7 @@ struct GpGraphics{
BOOL busy; /* hdc handle obtained by GdipGetDC */
GpRegion *clip;
UINT textcontrast; /* not used yet. get/set only */
+ struct list containers;
};
struct GpBrush{
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index 3525743..78c68be 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -38,6 +38,7 @@
#include "gdiplus.h"
#include "gdiplus_private.h"
#include "wine/debug.h"
+#include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
@@ -941,6 +942,141 @@ GpStatus trace_path(GpGraphics *graphics, GpPath *path)
return result;
}
+typedef struct _GraphicsContainerItem {
+ struct list entry;
+ GraphicsContainer contid;
+
+ SmoothingMode smoothing;
+ CompositingQuality compqual;
+ InterpolationMode interpolation;
+ CompositingMode compmode;
+ TextRenderingHint texthint;
+ REAL scale;
+ GpUnit unit;
+ PixelOffsetMode pixeloffset;
+ UINT textcontrast;
+ GpMatrix* worldtrans;
+ GpRegion* clip;
+} GraphicsContainerItem;
+
+typedef struct _GraphicsContainerID {
+ struct list entry;
+
+ GraphicsContainer id;
+} GraphicsContainerID;
+
+static struct list availableGCIDs = LIST_INIT(availableGCIDs);
+static GraphicsContainer lowest_unallocated_GCID = 0;
+
+static void make_available_gcid(GraphicsContainer id){
+ GraphicsContainerID *gcid;
+
+ gcid = GdipAlloc(sizeof(GraphicsContainerID));
+ gcid->id = id;
+ list_add_head(&availableGCIDs, &gcid->entry);
+}
+
+static void allocate_gcids(){
+ const GraphicsContainer num_new_ids = 20;
+ GraphicsContainer i;
+
+ for(i = 0; i < num_new_ids; i++){
+ make_available_gcid(i + lowest_unallocated_GCID);
+ }
+
+ lowest_unallocated_GCID += num_new_ids;
+}
+
+static void get_available_gcid(GraphicsContainer* id){
+ GraphicsContainerID *gcid;
+
+ if(list_empty(&availableGCIDs))
+ allocate_gcids();
+
+ gcid = LIST_ENTRY(list_head(&availableGCIDs), GraphicsContainerID, entry);
+ *id = gcid->id;
+ list_remove(&gcid->entry);
+ GdipFree(gcid);
+}
+
+static GpStatus init_container(GraphicsContainerItem** container,
+ GDIPCONST GpGraphics* graphics){
+ GpStatus sts;
+
+ *container = GdipAlloc(sizeof(GraphicsContainerItem));
+ if(!(*container))
+ return OutOfMemory;
+
+ get_available_gcid(&(*container)->contid);
+
+ (*container)->smoothing = graphics->smoothing;
+ (*container)->compqual = graphics->compqual;
+ (*container)->interpolation = graphics->interpolation;
+ (*container)->compmode = graphics->compmode;
+ (*container)->texthint = graphics->texthint;
+ (*container)->scale = graphics->scale;
+ (*container)->unit = graphics->unit;
+ (*container)->textcontrast = graphics->textcontrast;
+ (*container)->pixeloffset = graphics->pixeloffset;
+
+ sts = GdipCloneMatrix(graphics->worldtrans, &(*container)->worldtrans);
+ if(sts != Ok){
+ GdipFree(*container);
+ *container = NULL;
+ return sts;
+ }
+
+ sts = GdipCloneRegion(graphics->clip, &(*container)->clip);
+ if(sts != Ok){
+ GdipDeleteMatrix((*container)->worldtrans);
+ GdipFree(*container);
+ *container = NULL;
+ return sts;
+ }
+
+ return Ok;
+}
+
+static void delete_container(GraphicsContainerItem* container){
+ make_available_gcid(container->contid);
+ GdipDeleteMatrix(container->worldtrans);
+ GdipDeleteRegion(container->clip);
+ GdipFree(container);
+}
+
+static GpStatus restore_container(GpGraphics* graphics,
+ GDIPCONST GraphicsContainerItem* container){
+ GpStatus sts;
+ GpMatrix *newTrans;
+ GpRegion *newClip;
+
+ sts = GdipCloneMatrix(container->worldtrans, &newTrans);
+ if(sts != Ok)
+ return sts;
+
+ sts = GdipCloneRegion(container->clip, &newClip);
+ if(sts != Ok)
+ return sts;
+
+ GdipDeleteMatrix(graphics->worldtrans);
+ graphics->worldtrans = newTrans;
+
+ GdipDeleteRegion(graphics->clip);
+ graphics->clip = newClip;
+
+ graphics->smoothing = container->smoothing;
+ graphics->compqual = container->compqual;
+ graphics->interpolation = container->interpolation;
+ graphics->compmode = container->compmode;
+ graphics->texthint = container->texthint;
+ graphics->scale = container->scale;
+ graphics->unit = container->unit;
+ graphics->textcontrast = container->textcontrast;
+ graphics->pixeloffset = container->pixeloffset;
+
+ return Ok;
+}
+
GpStatus WINGDIPAPI GdipCreateFromHDC(HDC hdc, GpGraphics **graphics)
{
TRACE("(%p, %p)\n", hdc, graphics);
@@ -991,6 +1127,7 @@ GpStatus WINGDIPAPI GdipCreateFromHDC2(HDC hdc, HANDLE hDevice, GpGraphics **gra
(*graphics)->scale = 1.0;
(*graphics)->busy = FALSE;
(*graphics)->textcontrast = 4;
+ list_init(&(*graphics)->containers);
return Ok;
}
@@ -1155,6 +1292,7 @@ GpStatus WINGDIPAPI GdipCreateStreamOnFile(GDIPCONST WCHAR * filename,
GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics)
{
+ GraphicsContainerItem *cont, *next;
TRACE("(%p)\n", graphics);
if(!graphics) return InvalidParameter;
@@ -1163,6 +1301,11 @@ GpStatus WINGDIPAPI GdipDeleteGraphics(GpGraphics *graphics)
if(graphics->owndc)
ReleaseDC(graphics->hwnd, graphics->hdc);
+ LIST_FOR_EACH_ENTRY_SAFE(cont, next, &graphics->containers, GraphicsContainerItem, entry){
+ list_remove(&cont->entry);
+ delete_container(cont);
+ }
+
GdipDeleteRegion(graphics->clip);
GdipDeleteMatrix(graphics->worldtrans);
GdipFree(graphics);
@@ -3254,14 +3397,24 @@ GpStatus WINGDIPAPI GdipSaveGraphics(GpGraphics *graphics, GraphicsState *state)
return Ok;
}
-GpStatus WINGDIPAPI GdipBeginContainer2(GpGraphics *graphics, GraphicsContainer *state)
+GpStatus WINGDIPAPI GdipBeginContainer2(GpGraphics *graphics,
+ GraphicsContainer *state)
{
- FIXME("(%p, %p)\n", graphics, state);
+ GraphicsContainerItem *container;
+ GpStatus sts;
+
+ TRACE("(%p, %p)\n", graphics, state);
if(!graphics || !state)
return InvalidParameter;
- *state = 0xdeadbeef;
+ sts = init_container(&container, graphics);
+ if(sts != Ok)
+ return sts;
+
+ list_add_head(&graphics->containers, &container->entry);
+ *state = container->contid;
+
return Ok;
}
@@ -3285,12 +3438,36 @@ GpStatus WINGDIPAPI GdipComment(GpGraphics *graphics, UINT sizeData, GDIPCONST B
GpStatus WINGDIPAPI GdipEndContainer(GpGraphics *graphics, GraphicsState state)
{
- FIXME("(%p, 0x%x)\n", graphics, state);
+ GpStatus sts;
+ GraphicsContainerItem *container, *container2;
- if(!graphics || !state)
+ TRACE("(%p, %x)\n", graphics, state);
+
+ if(!graphics)
return InvalidParameter;
- return Ok;
+ LIST_FOR_EACH_ENTRY(container, &graphics->containers, GraphicsContainerItem, entry){
+ if(container->contid == state)
+ break;
+ }
+
+ /* did not find a matching container */
+ if(&container->entry == &graphics->containers)
+ return Ok;
+
+ /* remove all of the containers on top of the found container */
+ LIST_FOR_EACH_ENTRY_SAFE(container, container2, &graphics->containers, GraphicsContainerItem, entry){
+ if(container->contid == state)
+ break;
+ list_remove(&container->entry);
+ delete_container(container);
+ }
+
+ list_remove(&container->entry);
+ sts = restore_container(graphics, container);
+ delete_container(container);
+
+ return sts;
}
GpStatus WINGDIPAPI GdipScaleWorldTransform(GpGraphics *graphics, REAL sx,
diff --git a/include/gdiplusflat.h b/include/gdiplusflat.h
index 48c188b..0c1e54f 100644
--- a/include/gdiplusflat.h
+++ b/include/gdiplusflat.h
@@ -127,6 +127,7 @@ GpStatus WINGDIPAPI GdipFlush(GpGraphics*, GpFlushIntention);
GpStatus WINGDIPAPI GdipBeginContainer(GpGraphics*,GDIPCONST GpRectF*,GDIPCONST GpRectF*,GpUnit,GraphicsContainer*);
GpStatus WINGDIPAPI GdipBeginContainer2(GpGraphics*,GraphicsContainer*);
GpStatus WINGDIPAPI GdipBeginContainerI(GpGraphics*,GDIPCONST GpRect*,GDIPCONST GpRect*,GpUnit,GraphicsContainer*);
+GpStatus WINGDIPAPI GdipEndContainer(GpGraphics*,GraphicsContainer);
GpStatus WINGDIPAPI GdipComment(GpGraphics*,UINT,GDIPCONST BYTE*);
GpStatus WINGDIPAPI GdipCreateFromHDC(HDC,GpGraphics**);
GpStatus WINGDIPAPI GdipCreateFromHDC2(HDC,HANDLE,GpGraphics**);
--
1.6.3.3