xref: /reactos/dll/win32/gdiplus/gdiplus_private.h (revision fb5d5ecd)
1 /*
2  * Copyright (C) 2007 Google (Evan Stade)
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #ifndef __WINE_GP_PRIVATE_H_
20 #define __WINE_GP_PRIVATE_H_
21 
22 #include <math.h>
23 #include <stdarg.h>
24 
25 #include "windef.h"
26 #include "wingdi.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 
30 #include "objbase.h"
31 #include "ocidl.h"
32 #include "wincodecsdk.h"
33 #include "wine/heap.h"
34 #include "wine/list.h"
35 
36 #include "gdiplus.h"
37 
38 #define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
39 
40 #define GP_DEFAULT_PENSTYLE (PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT | PS_JOIN_MITER)
41 #define MAX_ARC_PTS (13)
42 #define MAX_DASHLEN (16) /* this is a limitation of gdi */
43 #define INCH_HIMETRIC (2540)
44 
45 #define VERSION_MAGIC  0xdbc01001
46 #define VERSION_MAGIC2 0xdbc01002
47 #define VALID_MAGIC(x) (((x) & 0xfffff000) == 0xdbc01000)
48 #define TENSION_CONST (0.3)
49 
50 #define GIF_DISPOSE_UNSPECIFIED 0
51 #define GIF_DISPOSE_DO_NOT_DISPOSE 1
52 #define GIF_DISPOSE_RESTORE_TO_BKGND 2
53 #define GIF_DISPOSE_RESTORE_TO_PREV 3
54 
55 
56 COLORREF ARGB2COLORREF(ARGB color) DECLSPEC_HIDDEN;
57 HBITMAP ARGB2BMP(ARGB color) DECLSPEC_HIDDEN;
58 extern INT arc2polybezier(GpPointF * points, REAL x1, REAL y1, REAL x2, REAL y2,
59     REAL startAngle, REAL sweepAngle) DECLSPEC_HIDDEN;
60 extern REAL gdiplus_atan2(REAL dy, REAL dx) DECLSPEC_HIDDEN;
61 extern GpStatus hresult_to_status(HRESULT res) DECLSPEC_HIDDEN;
62 extern REAL units_to_pixels(REAL units, GpUnit unit, REAL dpi) DECLSPEC_HIDDEN;
63 extern REAL pixels_to_units(REAL pixels, GpUnit unit, REAL dpi) DECLSPEC_HIDDEN;
64 extern REAL units_scale(GpUnit from, GpUnit to, REAL dpi) DECLSPEC_HIDDEN;
65 
66 #define WineCoordinateSpaceGdiDevice ((GpCoordinateSpace)4)
67 
68 extern GpStatus gdi_transform_acquire(GpGraphics *graphics);
69 extern GpStatus gdi_transform_release(GpGraphics *graphics);
70 extern GpStatus get_graphics_transform(GpGraphics *graphics, GpCoordinateSpace dst_space,
71         GpCoordinateSpace src_space, GpMatrix *matrix) DECLSPEC_HIDDEN;
72 extern GpStatus gdip_transform_points(GpGraphics *graphics, GpCoordinateSpace dst_space,
73         GpCoordinateSpace src_space, GpPointF *points, INT count) DECLSPEC_HIDDEN;
74 
75 extern GpStatus graphics_from_image(GpImage *image, GpGraphics **graphics) DECLSPEC_HIDDEN;
76 extern GpStatus encode_image_png(GpImage *image, IStream* stream, GDIPCONST EncoderParameters* params) DECLSPEC_HIDDEN;
77 
78 extern GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **result) DECLSPEC_HIDDEN;
79 extern GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc) DECLSPEC_HIDDEN;
80 extern GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc) DECLSPEC_HIDDEN;
81 extern GpStatus METAFILE_GraphicsClear(GpMetafile* metafile, ARGB color) DECLSPEC_HIDDEN;
82 extern GpStatus METAFILE_FillRectangles(GpMetafile* metafile, GpBrush* brush,
83     GDIPCONST GpRectF* rects, INT count) DECLSPEC_HIDDEN;
84 extern GpStatus METAFILE_SetClipRect(GpMetafile* metafile,
85     REAL x, REAL y, REAL width, REAL height, CombineMode mode) DECLSPEC_HIDDEN;
86 extern GpStatus METAFILE_SetClipRegion(GpMetafile* metafile, GpRegion* region, CombineMode mode) DECLSPEC_HIDDEN;
87 extern GpStatus METAFILE_SetPageTransform(GpMetafile* metafile, GpUnit unit, REAL scale) DECLSPEC_HIDDEN;
88 extern GpStatus METAFILE_SetWorldTransform(GpMetafile* metafile, GDIPCONST GpMatrix* transform) DECLSPEC_HIDDEN;
89 extern GpStatus METAFILE_ScaleWorldTransform(GpMetafile* metafile, REAL sx, REAL sy, MatrixOrder order) DECLSPEC_HIDDEN;
90 extern GpStatus METAFILE_MultiplyWorldTransform(GpMetafile* metafile, GDIPCONST GpMatrix* matrix, MatrixOrder order) DECLSPEC_HIDDEN;
91 extern GpStatus METAFILE_RotateWorldTransform(GpMetafile* metafile, REAL angle, MatrixOrder order) DECLSPEC_HIDDEN;
92 extern GpStatus METAFILE_TranslateWorldTransform(GpMetafile* metafile, REAL dx, REAL dy, MatrixOrder order) DECLSPEC_HIDDEN;
93 extern GpStatus METAFILE_ResetWorldTransform(GpMetafile* metafile) DECLSPEC_HIDDEN;
94 extern GpStatus METAFILE_BeginContainer(GpMetafile* metafile, GDIPCONST GpRectF *dstrect,
95     GDIPCONST GpRectF *srcrect, GpUnit unit, DWORD StackIndex) DECLSPEC_HIDDEN;
96 extern GpStatus METAFILE_BeginContainerNoParams(GpMetafile* metafile, DWORD StackIndex) DECLSPEC_HIDDEN;
97 extern GpStatus METAFILE_EndContainer(GpMetafile* metafile, DWORD StackIndex) DECLSPEC_HIDDEN;
98 extern GpStatus METAFILE_SaveGraphics(GpMetafile* metafile, DWORD StackIndex) DECLSPEC_HIDDEN;
99 extern GpStatus METAFILE_RestoreGraphics(GpMetafile* metafile, DWORD StackIndex) DECLSPEC_HIDDEN;
100 extern GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile) DECLSPEC_HIDDEN;
101 extern GpStatus METAFILE_DrawImagePointsRect(GpMetafile* metafile, GpImage *image,
102      GDIPCONST GpPointF *points, INT count, REAL srcx, REAL srcy, REAL srcwidth,
103      REAL srcheight, GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes,
104      DrawImageAbort callback, VOID *callbackData) DECLSPEC_HIDDEN;
105 extern GpStatus METAFILE_AddSimpleProperty(GpMetafile *metafile, SHORT prop, SHORT val) DECLSPEC_HIDDEN;
106 extern GpStatus METAFILE_DrawPath(GpMetafile *metafile, GpPen *pen, GpPath *path) DECLSPEC_HIDDEN;
107 extern GpStatus METAFILE_FillPath(GpMetafile *metafile, GpBrush *brush, GpPath *path) DECLSPEC_HIDDEN;
108 extern void METAFILE_Free(GpMetafile *metafile) DECLSPEC_HIDDEN;
109 
110 extern void calc_curve_bezier(const GpPointF *pts, REAL tension, REAL *x1,
111     REAL *y1, REAL *x2, REAL *y2) DECLSPEC_HIDDEN;
112 extern void calc_curve_bezier_endp(REAL xend, REAL yend, REAL xadj, REAL yadj,
113     REAL tension, REAL *x, REAL *y) DECLSPEC_HIDDEN;
114 
115 extern void free_installed_fonts(void) DECLSPEC_HIDDEN;
116 
117 extern BOOL lengthen_path(GpPath *path, INT len) DECLSPEC_HIDDEN;
118 
119 extern DWORD write_region_data(const GpRegion *region, void *data) DECLSPEC_HIDDEN;
120 extern DWORD write_path_data(GpPath *path, void *data) DECLSPEC_HIDDEN;
121 
122 extern GpStatus trace_path(GpGraphics *graphics, GpPath *path) DECLSPEC_HIDDEN;
123 
124 typedef struct region_element region_element;
125 extern void delete_element(region_element *element) DECLSPEC_HIDDEN;
126 
127 extern GpStatus get_hatch_data(GpHatchStyle hatchstyle, const char **result) DECLSPEC_HIDDEN;
128 
129 static inline INT gdip_round(REAL x)
130 {
131     return (INT) floorf(x + 0.5);
132 }
133 
134 static inline INT ceilr(REAL x)
135 {
136     return (INT) ceilf(x);
137 }
138 
139 static inline REAL deg2rad(REAL degrees)
140 {
141     return M_PI * degrees / 180.0;
142 }
143 
144 static inline ARGB color_over(ARGB bg, ARGB fg)
145 {
146     BYTE b, g, r, a;
147     BYTE bg_alpha, fg_alpha;
148 
149     fg_alpha = (fg>>24)&0xff;
150 
151     if (fg_alpha == 0xff) return fg;
152 
153     if (fg_alpha == 0) return bg;
154 
155     bg_alpha = (((bg>>24)&0xff) * (0xff-fg_alpha)) / 0xff;
156 
157     if (bg_alpha == 0) return fg;
158 
159     a = bg_alpha + fg_alpha;
160     b = ((bg&0xff)*bg_alpha + (fg&0xff)*fg_alpha)/a;
161     g = (((bg>>8)&0xff)*bg_alpha + ((fg>>8)&0xff)*fg_alpha)/a;
162     r = (((bg>>16)&0xff)*bg_alpha + ((fg>>16)&0xff)*fg_alpha)/a;
163 
164     return (a<<24)|(r<<16)|(g<<8)|b;
165 }
166 
167 /* fg is premult, bg and return value are not */
168 static inline ARGB color_over_fgpremult(ARGB bg, ARGB fg)
169 {
170     BYTE b, g, r, a;
171     BYTE bg_alpha, fg_alpha;
172 
173     fg_alpha = (fg>>24)&0xff;
174 
175     if (fg_alpha == 0) return bg;
176 
177     bg_alpha = (((bg>>24)&0xff) * (0xff-fg_alpha)) / 0xff;
178 
179     a = bg_alpha + fg_alpha;
180     b = ((bg&0xff)*bg_alpha + (fg&0xff)*0xff)/a;
181     g = (((bg>>8)&0xff)*bg_alpha + ((fg>>8)&0xff)*0xff)/a;
182     r = (((bg>>16)&0xff)*bg_alpha + ((fg>>16)&0xff)*0xff)/a;
183 
184     return (a<<24)|(r<<16)|(g<<8)|b;
185 }
186 
187 extern const char *debugstr_rectf(const RectF* rc) DECLSPEC_HIDDEN;
188 
189 extern const char *debugstr_pointf(const PointF* pt) DECLSPEC_HIDDEN;
190 
191 extern void convert_32bppARGB_to_32bppPARGB(UINT width, UINT height,
192     BYTE *dst_bits, INT dst_stride, const BYTE *src_bits, INT src_stride) DECLSPEC_HIDDEN;
193 
194 extern GpStatus convert_pixels(INT width, INT height,
195     INT dst_stride, BYTE *dst_bits, PixelFormat dst_format,
196     INT src_stride, const BYTE *src_bits, PixelFormat src_format, ColorPalette *palette) DECLSPEC_HIDDEN;
197 
198 extern PixelFormat apply_image_attributes(const GpImageAttributes *attributes, LPBYTE data,
199     UINT width, UINT height, INT stride, ColorAdjustType type, PixelFormat fmt) DECLSPEC_HIDDEN;
200 
201 struct GpMatrix{
202     REAL matrix[6];
203 };
204 
205 struct GpPen{
206     UINT style;
207     GpUnit unit;
208     REAL width;
209     GpLineCap endcap;
210     GpLineCap startcap;
211     GpDashCap dashcap;
212     GpCustomLineCap *customstart;
213     GpCustomLineCap *customend;
214     GpLineJoin join;
215     REAL miterlimit;
216     GpDashStyle dash;
217     REAL *dashes;
218     INT numdashes;
219     REAL offset;    /* dash offset */
220     GpBrush *brush;
221     GpPenAlignment align;
222     GpMatrix transform;
223 };
224 
225 struct GpGraphics{
226     HDC hdc;
227     HWND hwnd;
228     BOOL owndc;
229     BOOL alpha_hdc;
230     GpImage *image;
231     ImageType image_type;
232     SmoothingMode smoothing;
233     CompositingQuality compqual;
234     InterpolationMode interpolation;
235     PixelOffsetMode pixeloffset;
236     CompositingMode compmode;
237     TextRenderingHint texthint;
238     GpUnit unit;    /* page unit */
239     REAL scale;     /* page scale */
240     REAL xres, yres;
241     GpMatrix worldtrans; /* world transform */
242     BOOL busy;      /* hdc handle obtained by GdipGetDC */
243     GpRegion *clip; /* in device coords */
244     UINT textcontrast; /* not used yet. get/set only */
245     struct list containers;
246     GraphicsContainer contid; /* last-issued container ID */
247     INT origin_x, origin_y;
248     INT gdi_transform_acquire_count, gdi_transform_save;
249     GpMatrix gdi_transform;
250     HRGN gdi_clip;
251     /* For giving the caller an HDC when we technically can't: */
252     HBITMAP temp_hbitmap;
253     int temp_hbitmap_width;
254     int temp_hbitmap_height;
255     BYTE *temp_bits;
256     HDC temp_hdc;
257 };
258 
259 struct GpBrush{
260     GpBrushType bt;
261 };
262 
263 struct GpHatch{
264     GpBrush brush;
265     GpHatchStyle hatchstyle;
266     ARGB forecol;
267     ARGB backcol;
268 };
269 
270 struct GpSolidFill{
271     GpBrush brush;
272     ARGB color;
273 };
274 
275 struct GpPathGradient{
276     GpBrush brush;
277     GpPath* path;
278     ARGB centercolor;
279     GpWrapMode wrap;
280     BOOL gamma;
281     GpPointF center;
282     GpPointF focus;
283     REAL* blendfac;  /* blend factors */
284     REAL* blendpos;  /* blend positions */
285     INT blendcount;
286     ARGB *surroundcolors;
287     INT surroundcolorcount;
288     ARGB* pblendcolor; /* preset blend colors */
289     REAL* pblendpos; /* preset blend positions */
290     INT pblendcount;
291     GpMatrix transform;
292 };
293 
294 struct GpLineGradient{
295     GpBrush brush;
296     GpPointF startpoint;
297     GpPointF endpoint;
298     ARGB startcolor;
299     ARGB endcolor;
300     RectF rect;
301     GpWrapMode wrap;
302     BOOL gamma;
303     REAL* blendfac;  /* blend factors */
304     REAL* blendpos;  /* blend positions */
305     INT blendcount;
306     ARGB* pblendcolor; /* preset blend colors */
307     REAL* pblendpos; /* preset blend positions */
308     INT pblendcount;
309     GpMatrix transform;
310 };
311 
312 struct GpTexture{
313     GpBrush brush;
314     GpMatrix transform;
315     GpImage *image;
316     GpImageAttributes *imageattributes;
317     BYTE *bitmap_bits; /* image bits converted to ARGB and run through imageattributes */
318 };
319 
320 struct GpPath{
321     GpFillMode fill;
322     GpPathData pathdata;
323     BOOL newfigure; /* whether the next drawing action starts a new figure */
324     INT datalen; /* size of the arrays in pathdata */
325 };
326 
327 struct GpPathIterator{
328     GpPathData pathdata;
329     INT subpath_pos;    /* for NextSubpath methods */
330     INT marker_pos;     /* for NextMarker methods */
331     INT pathtype_pos;   /* for NextPathType methods */
332 };
333 
334 struct GpCustomLineCap{
335     CustomLineCapType type;
336     GpPathData pathdata;
337     BOOL fill;      /* TRUE for fill, FALSE for stroke */
338     GpLineCap cap;  /* as far as I can tell, this value is ignored */
339     REAL inset;     /* how much to adjust the end of the line */
340     GpLineJoin join;
341     REAL scale;
342 };
343 
344 struct GpAdjustableArrowCap{
345     GpCustomLineCap cap;
346     REAL middle_inset;
347     REAL height;
348     REAL width;
349 };
350 
351 struct GpImage{
352     IWICBitmapDecoder *decoder;
353     ImageType type;
354     GUID format;
355     UINT flags;
356     UINT frame_count, current_frame;
357     ColorPalette *palette;
358     REAL xres, yres;
359     LONG busy;
360 };
361 
362 #define EmfPlusObjectTableSize 64
363 
364 typedef enum EmfPlusObjectType
365 {
366     ObjectTypeInvalid,
367     ObjectTypeBrush,
368     ObjectTypePen,
369     ObjectTypePath,
370     ObjectTypeRegion,
371     ObjectTypeImage,
372     ObjectTypeFont,
373     ObjectTypeStringFormat,
374     ObjectTypeImageAttributes,
375     ObjectTypeCustomLineCap,
376     ObjectTypeMax = ObjectTypeCustomLineCap,
377 } EmfPlusObjectType;
378 
379 /* Deserialized EmfPlusObject record. */
380 struct emfplus_object {
381     EmfPlusObjectType type;
382     union {
383         GpBrush *brush;
384         GpPen *pen;
385         GpPath *path;
386         GpRegion *region;
387         GpImage *image;
388         GpFont *font;
389         GpImageAttributes *image_attributes;
390         void *object;
391     } u;
392 };
393 
394 struct GpMetafile{
395     GpImage image;
396     GpRectF bounds;
397     GpUnit unit;
398     MetafileType metafile_type;
399     HENHMETAFILE hemf;
400     int preserve_hemf; /* if true, hemf belongs to the app and should not be deleted */
401 
402     /* recording */
403     HDC record_dc;
404     GpGraphics *record_graphics;
405     BYTE *comment_data;
406     DWORD comment_data_size;
407     DWORD comment_data_length;
408     IStream *record_stream;
409     BOOL auto_frame; /* If true, determine the frame automatically */
410     GpPointF auto_frame_min, auto_frame_max;
411     DWORD next_object_id;
412 
413     /* playback */
414     GpGraphics *playback_graphics;
415     HDC playback_dc;
416     GpPointF playback_points[3];
417     GpRectF src_rect;
418     HANDLETABLE *handle_table;
419     int handle_count;
420     XFORM gdiworldtransform;
421     GpMatrix *world_transform;
422     GpUnit page_unit;
423     REAL page_scale;
424     GpRegion *base_clip; /* clip region in device space for all metafile output */
425     GpRegion *clip; /* clip region within the metafile */
426     struct list containers;
427     struct emfplus_object objtable[EmfPlusObjectTableSize];
428 };
429 
430 struct GpBitmap{
431     GpImage image;
432     INT width;
433     INT height;
434     PixelFormat format;
435     ImageLockMode lockmode;
436     BYTE *bitmapbits;   /* pointer to the buffer we passed in BitmapLockBits */
437     HBITMAP hbitmap;
438     HDC hdc;
439     BYTE *bits; /* actual image bits if this is a DIB */
440     INT stride; /* stride of bits if this is a DIB */
441     BYTE *own_bits; /* image bits that need to be freed with this object */
442     INT lockx, locky; /* X and Y coordinates of the rect when a bitmap is locked for writing. */
443     IWICMetadataReader *metadata_reader; /* NULL if there is no metadata */
444     UINT prop_count;
445     PropertyItem *prop_item; /* cached image properties */
446 };
447 
448 struct GpCachedBitmap{
449     GpImage *image;
450 };
451 
452 struct color_key{
453     BOOL enabled;
454     ARGB low;
455     ARGB high;
456 };
457 
458 struct color_matrix{
459     BOOL enabled;
460     ColorMatrixFlags flags;
461     ColorMatrix colormatrix;
462     ColorMatrix graymatrix;
463 };
464 
465 struct color_remap_table{
466     BOOL enabled;
467     INT mapsize;
468     ColorMap *colormap;
469 };
470 
471 enum imageattr_noop{
472     IMAGEATTR_NOOP_UNDEFINED,
473     IMAGEATTR_NOOP_SET,
474     IMAGEATTR_NOOP_CLEAR,
475 };
476 
477 struct GpImageAttributes{
478     WrapMode wrap;
479     ARGB outside_color;
480     BOOL clamp;
481     struct color_key colorkeys[ColorAdjustTypeCount];
482     struct color_matrix colormatrices[ColorAdjustTypeCount];
483     struct color_remap_table colorremaptables[ColorAdjustTypeCount];
484     BOOL gamma_enabled[ColorAdjustTypeCount];
485     REAL gamma[ColorAdjustTypeCount];
486     enum imageattr_noop noop[ColorAdjustTypeCount];
487 };
488 
489 struct GpFont{
490     GpFontFamily *family;
491     OUTLINETEXTMETRICW otm;
492     REAL emSize; /* in font units */
493     Unit unit;
494 };
495 
496 extern const struct GpStringFormat default_drawstring_format DECLSPEC_HIDDEN;
497 
498 struct GpStringFormat{
499     INT attr;
500     LANGID lang;
501     LANGID digitlang;
502     StringAlignment align;
503     StringTrimming trimming;
504     HotkeyPrefix hkprefix;
505     StringAlignment line_align;
506     StringDigitSubstitute digitsub;
507     INT tabcount;
508     REAL firsttab;
509     REAL *tabs;
510     CharacterRange *character_ranges;
511     INT range_count;
512     BOOL generic_typographic;
513 };
514 
515 extern void init_generic_string_formats(void) DECLSPEC_HIDDEN;
516 extern void free_generic_string_formats(void) DECLSPEC_HIDDEN;
517 
518 struct GpFontCollection{
519     GpFontFamily **FontFamilies;
520     INT count;
521     INT allocated;
522 };
523 
524 struct GpFontFamily{
525     WCHAR FamilyName[LF_FACESIZE];
526     UINT16 em_height, ascent, descent, line_spacing; /* in font units */
527     int dpi;
528 };
529 
530 /* internal use */
531 typedef enum RegionType
532 {
533     RegionDataRect          = 0x10000000,
534     RegionDataPath          = 0x10000001,
535     RegionDataEmptyRect     = 0x10000002,
536     RegionDataInfiniteRect  = 0x10000003,
537 } RegionType;
538 
539 struct region_element
540 {
541     DWORD type; /* Rectangle, Path, SpecialRectangle, or CombineMode */
542     union
543     {
544         GpRectF rect;
545         GpPath *path;
546         struct
547         {
548             struct region_element *left;  /* the original region */
549             struct region_element *right; /* what *left was combined with */
550         } combine;
551     } elementdata;
552 };
553 
554 struct GpRegion{
555     DWORD num_children;
556     region_element node;
557 };
558 
559 struct memory_buffer
560 {
561     const BYTE *buffer;
562     INT size, pos;
563 };
564 
565 static inline void init_memory_buffer(struct memory_buffer *mbuf, const BYTE *buffer, INT size)
566 {
567     mbuf->buffer = buffer;
568     mbuf->size = size;
569     mbuf->pos = 0;
570 }
571 
572 static inline const void *buffer_read(struct memory_buffer *mbuf, INT size)
573 {
574     if (mbuf->size - mbuf->pos >= size)
575     {
576         const void *data = mbuf->buffer + mbuf->pos;
577         mbuf->pos += size;
578         return data;
579     }
580     return NULL;
581 }
582 
583 typedef GpStatus (*gdip_format_string_callback)(HDC hdc,
584     GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
585     GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
586     INT lineno, const RectF *bounds, INT *underlined_indexes,
587     INT underlined_index_count, void *user_data);
588 
589 GpStatus gdip_format_string(HDC hdc,
590     GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font,
591     GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format, int ignore_empty_clip,
592     gdip_format_string_callback callback, void *user_data) DECLSPEC_HIDDEN;
593 
594 void get_log_fontW(const GpFont *, GpGraphics *, LOGFONTW *) DECLSPEC_HIDDEN;
595 
596 static inline BOOL image_lock(GpImage *image, BOOL *unlock)
597 {
598     LONG tid = GetCurrentThreadId(), owner_tid;
599     owner_tid = InterlockedCompareExchange(&image->busy, tid, 0);
600     *unlock = !owner_tid;
601     return !owner_tid || owner_tid==tid;
602 }
603 
604 static inline void image_unlock(GpImage *image, BOOL unlock)
605 {
606     if (unlock) image->busy = 0;
607 }
608 
609 #endif
610