Updated PostScript glyph name data.
[wine] / objects / gdiobj.c
1 /*
2  * GDI functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 #include "config.h"
8
9 #include <assert.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12
13 #include "windef.h"
14 #include "wingdi.h"
15 #include "winreg.h"
16 #include "winerror.h"
17 #include "wine/winbase16.h"
18
19 #include "bitmap.h"
20 #include "brush.h"
21 #include "font.h"
22 #include "heap.h"
23 #include "local.h"
24 #include "palette.h"
25 #include "pen.h"
26 #include "region.h"
27 #include "debugtools.h"
28 #include "gdi.h"
29
30 DEFAULT_DEBUG_CHANNEL(gdi);
31
32
33 /***********************************************************************
34  *          GDI stock objects 
35  */
36
37 static BRUSHOBJ WhiteBrush =
38 {
39     { 0, BRUSH_MAGIC, 1 },             /* header */
40     { BS_SOLID, RGB(255,255,255), 0 }  /* logbrush */
41 };
42
43 static BRUSHOBJ LtGrayBrush =
44 {
45     { 0, BRUSH_MAGIC, 1 },             /* header */
46 /* FIXME : this should perhaps be BS_HATCHED, at least for 1 bitperpixel */
47     { BS_SOLID, RGB(192,192,192), 0 }  /* logbrush */
48 };
49
50 static BRUSHOBJ GrayBrush =
51 {
52     { 0, BRUSH_MAGIC, 1 },             /* header */
53 /* FIXME : this should perhaps be BS_HATCHED, at least for 1 bitperpixel */
54     { BS_SOLID, RGB(128,128,128), 0 }  /* logbrush */
55 };
56
57 static BRUSHOBJ DkGrayBrush =
58 {
59     { 0, BRUSH_MAGIC, 1 },          /* header */
60 /* This is BS_HATCHED, for 1 bitperpixel. This makes the spray work in pbrush */
61 /* NB_HATCH_STYLES is an index into HatchBrushes */
62     { BS_HATCHED, RGB(0,0,0), NB_HATCH_STYLES }  /* logbrush */
63 };
64
65 static BRUSHOBJ BlackBrush =
66 {
67     { 0, BRUSH_MAGIC, 1 },       /* header */
68     { BS_SOLID, RGB(0,0,0), 0 }  /* logbrush */
69 };
70
71 static BRUSHOBJ NullBrush =
72 {
73     { 0, BRUSH_MAGIC, 1 },  /* header */
74     { BS_NULL, 0, 0 }       /* logbrush */
75 };
76
77 static PENOBJ WhitePen =
78 {
79     { 0, PEN_MAGIC, 1 },                     /* header */
80     { PS_SOLID, { 0, 0 }, RGB(255,255,255) } /* logpen */
81 };
82
83 static PENOBJ BlackPen =
84 {
85     { 0, PEN_MAGIC, 1 },               /* header */
86     { PS_SOLID, { 0, 0 }, RGB(0,0,0) } /* logpen */
87 };
88
89 static PENOBJ NullPen =
90 {
91     { 0, PEN_MAGIC, 1 },      /* header */
92     { PS_NULL, { 0, 0 }, 0 }  /* logpen */
93 };
94
95 static FONTOBJ OEMFixedFont =
96 {
97     { 0, FONT_MAGIC, 1 },   /* header */
98     { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, OEM_CHARSET,
99       0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, {'\0'} }
100 };
101
102 static FONTOBJ AnsiFixedFont =
103 {
104     { 0, FONT_MAGIC, 1 },   /* header */
105     { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
106       0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, {'\0'} }
107 };
108
109 static FONTOBJ AnsiVarFont =
110 {
111     { 0, FONT_MAGIC, 1 },   /* header */
112     { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
113       0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
114       {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'} }
115 };
116
117 static FONTOBJ SystemFont =
118 {
119     { 0, FONT_MAGIC, 1 },
120     { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
121       0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
122       {'S','y','s','t','e','m','\0'} }
123 };
124
125 static FONTOBJ DeviceDefaultFont =
126 {
127     { 0, FONT_MAGIC, 1 },   /* header */
128     { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
129       0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, {'\0'} }
130 };
131
132 static FONTOBJ SystemFixedFont =
133 {
134     { 0, FONT_MAGIC, 1 },   /* header */
135     { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
136       0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, {'\0'} }
137 };
138
139 /* FIXME: Is this correct? */
140 static FONTOBJ DefaultGuiFont =
141 {
142     { 0, FONT_MAGIC, 1 },   /* header */
143     { 0, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
144       0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
145       {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'} }
146 };
147
148
149 static GDIOBJHDR * StockObjects[NB_STOCK_OBJECTS] =
150 {
151     (GDIOBJHDR *) &WhiteBrush,
152     (GDIOBJHDR *) &LtGrayBrush,
153     (GDIOBJHDR *) &GrayBrush,
154     (GDIOBJHDR *) &DkGrayBrush,
155     (GDIOBJHDR *) &BlackBrush,
156     (GDIOBJHDR *) &NullBrush,
157     (GDIOBJHDR *) &WhitePen,
158     (GDIOBJHDR *) &BlackPen,
159     (GDIOBJHDR *) &NullPen,
160     NULL,
161     (GDIOBJHDR *) &OEMFixedFont,
162     (GDIOBJHDR *) &AnsiFixedFont,
163     (GDIOBJHDR *) &AnsiVarFont,
164     (GDIOBJHDR *) &SystemFont,
165     (GDIOBJHDR *) &DeviceDefaultFont,
166     NULL,            /* DEFAULT_PALETTE created by PALETTE_Init */
167     (GDIOBJHDR *) &SystemFixedFont,
168     (GDIOBJHDR *) &DefaultGuiFont
169 };
170
171 HBITMAP hPseudoStockBitmap; /* 1x1 bitmap for memory DCs */
172
173 static SYSLEVEL GDI_level = { CRITICAL_SECTION_INIT, 3 };
174 static WORD GDI_HeapSel;
175
176 static BOOL get_bool(char *buffer, BOOL def_value)
177 {
178     switch(buffer[0])
179     {
180         case 'n':
181         case 'N':
182         case 'f':
183         case 'F':
184         case '0':
185             return FALSE;
186
187         case 'y':
188         case 'Y':
189         case 't':
190         case 'T':
191         case '1':
192             return TRUE;
193
194         default:
195             return def_value;
196     }
197 }
198
199 /******************************************************************************
200  *
201  *   void  ReadFontInformation(
202  *      char const  *fontName,
203  *      FONTOBJ  *font,
204  *      int  defHeight,
205  *      int  defBold,
206  *      int  defItalic,
207  *      int  defUnderline,
208  *      int  defStrikeOut )
209  *
210  *   ReadFontInformation() checks the Wine configuration file's Tweak.Fonts
211  *   section for entries containing fontName.Height, fontName.Bold, etc.,
212  *   where fontName is the name specified in the call (e.g., "System").  It
213  *   attempts to be user friendly by accepting 'n', 'N', 'f', 'F', or '0' as
214  *   the first character in the boolean attributes (bold, italic, and
215  *   underline).
216  *****************************************************************************/
217
218 static void  ReadFontInformation(
219     char const *fontName,
220     FONTOBJ *font,
221     int  defHeight,
222     int  defBold,
223     int  defItalic,
224     int  defUnderline,
225     int  defStrikeOut )
226 {
227     char  key[256];
228     char buffer[MAX_PATH];
229     HKEY hkey;
230     DWORD type, count;
231
232     /* In order for the stock fonts to be independent of 
233      * mapping mode, the height (& width) must be 0
234      */
235
236     /* assign defaults */
237     font->logfont.lfHeight = defHeight;
238     font->logfont.lfWeight = defBold;
239     font->logfont.lfItalic = defItalic;
240     font->logfont.lfUnderline = defUnderline;
241     font->logfont.lfStrikeOut = defStrikeOut;
242
243     if(RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\Tweak.Fonts", &hkey))
244         return;
245
246     sprintf(key, "%s.Height", fontName);
247     count = sizeof(buffer);
248     if(!RegQueryValueExA(hkey, key, 0, &type, buffer, &count))
249         font->logfont.lfHeight = atoi(buffer);
250
251     sprintf(key, "%s.Bold", fontName);
252     count = sizeof(buffer);
253     if(!RegQueryValueExA(hkey, key, 0, &type, buffer, &count))
254         font->logfont.lfWeight = get_bool(buffer, defBold) ? FW_BOLD : FW_NORMAL;
255
256     sprintf(key, "%s.Italic", fontName);
257     count = sizeof(buffer);
258     if(!RegQueryValueExA(hkey, key, 0, &type, buffer, &count))
259         font->logfont.lfItalic = get_bool(buffer, defItalic);
260
261     sprintf(key, "%s.Underline", fontName);
262     count = sizeof(buffer);
263     if(!RegQueryValueExA(hkey, key, 0, &type, buffer, &count))
264         font->logfont.lfUnderline = get_bool(buffer, defUnderline);
265
266     sprintf(key, "%s.StrikeOut", fontName);
267     count = sizeof(buffer);
268     if(!RegQueryValueExA(hkey, key, 0, &type, buffer, &count))
269         font->logfont.lfStrikeOut = get_bool(buffer, defStrikeOut);
270
271     RegCloseKey(hkey);
272 }
273
274 /***********************************************************************
275  * Because the stock fonts have their structure initialized with
276  * a height of 0 to keep them independent of mapping mode, simply
277  * returning the LOGFONT as is will not work correctly.
278  * These "FixStockFontSizeXXX()" methods will get the correct
279  * size for the fonts.
280  */
281 static void GetFontMetrics(HFONT handle, LPTEXTMETRICA lptm)
282 {
283   HDC         hdc;
284   HFONT       hOldFont;
285
286   hdc = CreateDCA("DISPLAY", NULL, NULL, NULL);
287
288   hOldFont = (HFONT)SelectObject(hdc, handle);
289
290   GetTextMetricsA(hdc, lptm);
291
292   SelectObject(hdc, hOldFont);
293
294   DeleteDC(hdc);
295 }
296
297 static inline void FixStockFontSize16(
298   HFONT  handle, 
299   INT16  count, 
300   LPVOID buffer)
301 {
302   TEXTMETRICA tm;
303   LOGFONT16*  pLogFont = (LOGFONT16*)buffer;
304
305   /*
306    * Was the lfHeight field copied (it's the first field)?
307    * If it was and it was null, replace the height.
308    */
309   if ( (count >= 2*sizeof(INT16)) &&
310        (pLogFont->lfHeight == 0) )
311   {
312     GetFontMetrics(handle, &tm);
313     
314     pLogFont->lfHeight = tm.tmHeight;
315     pLogFont->lfWidth  = tm.tmAveCharWidth;
316   }
317 }
318
319 static inline void FixStockFontSizeA(
320   HFONT  handle, 
321   INT    count, 
322   LPVOID buffer)
323 {
324   TEXTMETRICA tm;
325   LOGFONTA*  pLogFont = (LOGFONTA*)buffer;
326
327   /*
328    * Was the lfHeight field copied (it's the first field)?
329    * If it was and it was null, replace the height.
330    */
331   if ( (count >= 2*sizeof(INT)) &&
332        (pLogFont->lfHeight == 0) )
333   {
334     GetFontMetrics(handle, &tm);
335
336     pLogFont->lfHeight = tm.tmHeight;
337     pLogFont->lfWidth  = tm.tmAveCharWidth;
338   }
339 }
340
341 /**
342  * Since the LOGFONTA and LOGFONTW structures are identical up to the 
343  * lfHeight member (the one of interest in this case) we simply define
344  * the W version as the A version. 
345  */
346 #define FixStockFontSizeW FixStockFontSizeA
347
348 #define TRACE_SEC(handle,text) \
349    TRACE("(%04x): " text " %ld\n", (handle), GDI_level.crst.RecursionCount)
350
351 /***********************************************************************
352  *           GDI_Init
353  *
354  * GDI initialization.
355  */
356 BOOL GDI_Init(void)
357 {
358     HPALETTE16 hpalette;
359     HINSTANCE16 instance;
360
361     /* create GDI heap */
362     if ((instance = LoadLibrary16( "GDI.EXE" )) < 32) return FALSE;
363     GDI_HeapSel = instance | 7;
364
365     /* TWEAK: Initialize font hints */
366     ReadFontInformation("OEMFixed", &OEMFixedFont, 0, 0, 0, 0, 0);
367     ReadFontInformation("AnsiFixed", &AnsiFixedFont, 0, 0, 0, 0, 0);
368     ReadFontInformation("AnsiVar", &AnsiVarFont, 0, 0, 0, 0, 0);
369     ReadFontInformation("System", &SystemFont, 0, 0, 0, 0, 0);
370     ReadFontInformation("DeviceDefault", &DeviceDefaultFont, 0, 0, 0, 0, 0);
371     ReadFontInformation("SystemFixed", &SystemFixedFont, 0, 0, 0, 0, 0);
372     ReadFontInformation("DefaultGui", &DefaultGuiFont, 0, 0, 0, 0, 0);
373
374     /* Create default palette */
375
376     /* DR well *this* palette can't be moveable (?) */
377     hpalette = PALETTE_Init();
378     if( !hpalette ) return FALSE;
379     StockObjects[DEFAULT_PALETTE] = (GDIOBJHDR *)LOCAL_Lock( GDI_HeapSel, hpalette );
380
381     hPseudoStockBitmap = CreateBitmap( 1, 1, 1, 1, NULL ); 
382     return TRUE;
383 }
384
385 #define FIRST_LARGE_HANDLE 16
386 #define MAX_LARGE_HANDLES ((GDI_HEAP_SIZE >> 2) - FIRST_LARGE_HANDLE)
387 static GDIOBJHDR *large_handles[MAX_LARGE_HANDLES];
388 static int next_large_handle;
389
390 /***********************************************************************
391  *           alloc_large_heap
392  *
393  * Allocate a GDI handle from the large heap. Helper for GDI_AllocObject
394  */
395 inline static GDIOBJHDR *alloc_large_heap( WORD size, HGDIOBJ *handle )
396 {
397     int i;
398     GDIOBJHDR *obj;
399
400     for (i = next_large_handle + 1; i < MAX_LARGE_HANDLES; i++)
401         if (!large_handles[i]) goto found;
402     for (i = 0; i <= next_large_handle; i++)
403         if (!large_handles[i]) goto found;
404     *handle = 0;
405     return NULL;
406
407  found:
408     if ((obj = HeapAlloc( GetProcessHeap(), 0, size )))
409     {
410         large_handles[i] = obj;
411         *handle = (i + FIRST_LARGE_HANDLE) << 2;
412         next_large_handle = i;
413     }
414     return obj;
415 }
416
417
418 /***********************************************************************
419  *           GDI_AllocObject
420  */
421 void *GDI_AllocObject( WORD size, WORD magic, HGDIOBJ *handle )
422 {
423     static DWORD count = 0;
424     GDIOBJHDR *obj;
425
426     _EnterSysLevel( &GDI_level );
427     switch(magic)
428     {
429         /* allocate DCs on the larger heap */
430     case DC_MAGIC:
431     case DISABLED_DC_MAGIC:
432     case META_DC_MAGIC:
433     case METAFILE_MAGIC:
434     case METAFILE_DC_MAGIC:
435     case ENHMETAFILE_MAGIC:
436     case ENHMETAFILE_DC_MAGIC:
437     case BITMAP_MAGIC:   
438         if (!(obj = alloc_large_heap( size, handle ))) goto error;
439         break;
440     default:
441         if (!(*handle = LOCAL_Alloc( GDI_HeapSel, LMEM_MOVEABLE, size ))) goto error;
442         assert( *handle & 2 );
443         obj = (GDIOBJHDR *)LOCAL_Lock( GDI_HeapSel, *handle );
444         break;
445     }
446
447     obj->hNext   = 0;
448     obj->wMagic  = magic|OBJECT_NOSYSTEM;
449     obj->dwCount = ++count;
450
451     TRACE_SEC( *handle, "enter" );
452     return obj;
453
454 error:
455     _LeaveSysLevel( &GDI_level );
456     *handle = 0;
457     return NULL;
458 }
459
460
461 /***********************************************************************
462  *           GDI_ReallocObject
463  *
464  * The object ptr must have been obtained with GDI_GetObjPtr.
465  * The new pointer must be released with GDI_ReleaseObj.
466  */
467 void *GDI_ReallocObject( WORD size, HGDIOBJ handle, void *object )
468 {
469     HGDIOBJ new_handle;
470
471     assert( handle & 2 );  /* no realloc for large handles */
472     LOCAL_Unlock( GDI_HeapSel, handle );
473     if (!(new_handle = LOCAL_ReAlloc( GDI_HeapSel, handle, size, LMEM_MOVEABLE )))
474     {
475         TRACE_SEC( handle, "leave" );
476         _LeaveSysLevel( &GDI_level );
477         return NULL;
478     }
479     assert( new_handle == handle );  /* moveable handle cannot change */
480     return LOCAL_Lock( GDI_HeapSel, handle );
481 }
482  
483
484 /***********************************************************************
485  *           GDI_FreeObject
486  */
487 BOOL GDI_FreeObject( HGDIOBJ handle, void *ptr )
488 {
489     GDIOBJHDR *object = ptr;
490
491     /* can't free stock objects */
492     if (handle < FIRST_STOCK_HANDLE)
493     {
494         object->wMagic = 0;  /* Mark it as invalid */
495         if (handle & 2)  /* GDI heap handle */
496         {
497             LOCAL_Unlock( GDI_HeapSel, handle );
498             LOCAL_Free( GDI_HeapSel, handle );
499         }
500         else  /* large heap handle */
501         {
502             int i = (handle >> 2) - FIRST_LARGE_HANDLE;
503             if (i >= 0 && large_handles[i])
504             {
505                 HeapFree( GetProcessHeap(), 0, large_handles[i] );
506                 large_handles[i] = NULL;
507             }
508         }
509     }
510     TRACE_SEC( handle, "leave" );
511     _LeaveSysLevel( &GDI_level );
512     return TRUE;
513 }
514
515
516 /***********************************************************************
517  *           GDI_GetObjPtr
518  *
519  * Return a pointer to the GDI object associated to the handle.
520  * Return NULL if the object has the wrong magic number.
521  * The object must be released with GDI_ReleaseObj.
522  */
523 void *GDI_GetObjPtr( HGDIOBJ handle, WORD magic )
524 {
525     GDIOBJHDR *ptr = NULL;
526
527     _EnterSysLevel( &GDI_level );
528
529     if (handle >= FIRST_STOCK_HANDLE)
530     {
531         if (handle <= LAST_STOCK_HANDLE) ptr = StockObjects[handle - FIRST_STOCK_HANDLE];
532         if (ptr && (magic != MAGIC_DONTCARE)
533         && (GDIMAGIC(ptr->wMagic) != magic)) ptr = NULL;
534     }
535     else if (handle & 2)  /* GDI heap handle */
536     {
537         ptr = (GDIOBJHDR *)LOCAL_Lock( GDI_HeapSel, handle );
538         if (ptr &&
539         (magic != MAGIC_DONTCARE) && (GDIMAGIC(ptr->wMagic) != magic))
540         {
541             LOCAL_Unlock( GDI_HeapSel, handle );
542             ptr = NULL;
543         }
544     }
545     else  /* large heap handle */
546     {
547         int i = (handle >> 2) - FIRST_LARGE_HANDLE;
548         if (i >= 0)
549         {
550             ptr = large_handles[i];
551             if (ptr && (magic != MAGIC_DONTCARE) && (GDIMAGIC(ptr->wMagic) != magic)) ptr = NULL;
552         }
553     }
554
555     if (!ptr)
556     {
557         _LeaveSysLevel( &GDI_level );
558         SetLastError( ERROR_INVALID_HANDLE );
559     }
560     else TRACE_SEC( handle, "enter" );
561
562     return ptr;
563 }
564
565
566 /***********************************************************************
567  *           GDI_ReleaseObj
568  *
569  */
570 void GDI_ReleaseObj( HGDIOBJ handle )
571 {
572     if (handle < FIRST_STOCK_HANDLE && (handle & 2)) LOCAL_Unlock( GDI_HeapSel, handle );
573     TRACE_SEC( handle, "leave" );
574     _LeaveSysLevel( &GDI_level );
575 }
576
577
578 /***********************************************************************
579  *           DeleteObject16    (GDI.605)
580  */
581 BOOL16 WINAPI DeleteObject16( HGDIOBJ16 obj )
582 {
583     return DeleteObject( obj );
584 }
585
586
587 /***********************************************************************
588  *           DeleteObject    (GDI32.@)
589  */
590 BOOL WINAPI DeleteObject( HGDIOBJ obj )
591 {
592       /* Check if object is valid */
593
594     GDIOBJHDR * header;
595     if (HIWORD(obj)) return FALSE;
596     if ((obj >= FIRST_STOCK_HANDLE) && (obj <= LAST_STOCK_HANDLE)) {
597         TRACE("Preserving Stock object %04x\n", obj );
598         /* NOTE: No GDI_Release is necessary */
599         return TRUE;
600     }
601     if (obj == hPseudoStockBitmap) return TRUE;
602     if (!(header = GDI_GetObjPtr( obj, MAGIC_DONTCARE ))) return FALSE;
603
604     if (!(header->wMagic & OBJECT_NOSYSTEM)
605     &&   (header->wMagic >= FIRST_MAGIC) && (header->wMagic <= LAST_MAGIC))
606     {
607         TRACE("Preserving system object %04x\n", obj);
608         GDI_ReleaseObj( obj );
609         return TRUE;
610     }
611         
612     TRACE("%04x\n", obj );
613
614       /* Delete object */
615
616     switch(GDIMAGIC(header->wMagic))
617     {
618       case PEN_MAGIC:     return GDI_FreeObject( obj, header );
619       case BRUSH_MAGIC:   return BRUSH_DeleteObject( obj, (BRUSHOBJ*)header );
620       case FONT_MAGIC:    return GDI_FreeObject( obj, header );
621       case PALETTE_MAGIC: return PALETTE_DeleteObject(obj,(PALETTEOBJ*)header);
622       case BITMAP_MAGIC:  return BITMAP_DeleteObject( obj, (BITMAPOBJ*)header);
623       case REGION_MAGIC:  return REGION_DeleteObject( obj, (RGNOBJ*)header );
624       case DC_MAGIC:
625           GDI_ReleaseObj( obj );
626           return DeleteDC(obj);
627       case 0 :
628         WARN("Already deleted\n");
629         break;
630       default:
631         WARN("Unknown magic number (%d)\n",GDIMAGIC(header->wMagic));
632     }
633     GDI_ReleaseObj( obj );
634     return FALSE;
635 }
636
637 /***********************************************************************
638  *           GetStockObject16    (GDI.87)
639  */
640 HGDIOBJ16 WINAPI GetStockObject16( INT16 obj )
641 {
642     return (HGDIOBJ16)GetStockObject( obj );
643 }
644
645
646 /***********************************************************************
647  *           GetStockObject    (GDI32.@)
648  */
649 HGDIOBJ WINAPI GetStockObject( INT obj )
650 {
651     HGDIOBJ ret;
652     if ((obj < 0) || (obj >= NB_STOCK_OBJECTS)) return 0;
653     if (!StockObjects[obj]) return 0;
654     ret = (HGDIOBJ16)(FIRST_STOCK_HANDLE + obj);
655     TRACE("returning %4x\n", ret );
656     return ret;
657 }
658
659
660 /***********************************************************************
661  *           GetObject16    (GDI.82)
662  */
663 INT16 WINAPI GetObject16( HANDLE16 handle, INT16 count, LPVOID buffer )
664 {
665     GDIOBJHDR * ptr;
666     INT16 result = 0;
667     TRACE("%04x %d %p\n", handle, count, buffer );
668     if (!count) return 0;
669
670     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
671     
672     switch(GDIMAGIC(ptr->wMagic))
673       {
674       case PEN_MAGIC:
675         result = PEN_GetObject16( (PENOBJ *)ptr, count, buffer );
676         break;
677       case BRUSH_MAGIC: 
678         result = BRUSH_GetObject16( (BRUSHOBJ *)ptr, count, buffer );
679         break;
680       case BITMAP_MAGIC: 
681         result = BITMAP_GetObject16( (BITMAPOBJ *)ptr, count, buffer );
682         break;
683       case FONT_MAGIC:
684         result = FONT_GetObject16( (FONTOBJ *)ptr, count, buffer );
685         
686         /*
687          * Fix the LOGFONT structure for the stock fonts
688          */
689         if ( (handle >= FIRST_STOCK_HANDLE) && 
690              (handle <= LAST_STOCK_HANDLE) )
691           FixStockFontSize16(handle, count, buffer);    
692         break;
693       case PALETTE_MAGIC:
694         result = PALETTE_GetObject( (PALETTEOBJ *)ptr, count, buffer );
695         break;
696       }
697     GDI_ReleaseObj( handle );
698     return result;
699 }
700
701
702 /***********************************************************************
703  *           GetObjectA    (GDI32.@)
704  */
705 INT WINAPI GetObjectA( HANDLE handle, INT count, LPVOID buffer )
706 {
707     GDIOBJHDR * ptr;
708     INT result = 0;
709     TRACE("%08x %d %p\n", handle, count, buffer );
710     if (!count) return 0;
711
712     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
713
714     switch(GDIMAGIC(ptr->wMagic))
715     {
716       case PEN_MAGIC:
717           result = PEN_GetObject( (PENOBJ *)ptr, count, buffer );
718           break;
719       case BRUSH_MAGIC: 
720           result = BRUSH_GetObject( (BRUSHOBJ *)ptr, count, buffer );
721           break;
722       case BITMAP_MAGIC: 
723           result = BITMAP_GetObject( (BITMAPOBJ *)ptr, count, buffer );
724           break;
725       case FONT_MAGIC:
726           result = FONT_GetObjectA( (FONTOBJ *)ptr, count, buffer );
727           
728           /*
729            * Fix the LOGFONT structure for the stock fonts
730            */
731           if ( (handle >= FIRST_STOCK_HANDLE) && 
732                (handle <= LAST_STOCK_HANDLE) )
733             FixStockFontSizeA(handle, count, buffer);
734           break;
735       case PALETTE_MAGIC:
736           result = PALETTE_GetObject( (PALETTEOBJ *)ptr, count, buffer );
737           break;
738
739       case REGION_MAGIC:
740       case DC_MAGIC:
741       case DISABLED_DC_MAGIC:
742       case META_DC_MAGIC:
743       case METAFILE_MAGIC:
744       case METAFILE_DC_MAGIC:
745       case ENHMETAFILE_MAGIC:
746       case ENHMETAFILE_DC_MAGIC:
747           FIXME("Magic %04x not implemented\n", GDIMAGIC(ptr->wMagic) );
748           break;
749
750       default:
751           ERR("Invalid GDI Magic %04x\n", GDIMAGIC(ptr->wMagic));
752           break;
753     }
754     GDI_ReleaseObj( handle );
755     return result;
756 }
757
758 /***********************************************************************
759  *           GetObjectW    (GDI32.@)
760  */
761 INT WINAPI GetObjectW( HANDLE handle, INT count, LPVOID buffer )
762 {
763     GDIOBJHDR * ptr;
764     INT result = 0;
765     TRACE("%08x %d %p\n", handle, count, buffer );
766     if (!count) return 0;
767
768     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
769
770     switch(GDIMAGIC(ptr->wMagic))
771     {
772       case PEN_MAGIC:
773           result = PEN_GetObject( (PENOBJ *)ptr, count, buffer );
774           break;
775       case BRUSH_MAGIC: 
776           result = BRUSH_GetObject( (BRUSHOBJ *)ptr, count, buffer );
777           break;
778       case BITMAP_MAGIC: 
779           result = BITMAP_GetObject( (BITMAPOBJ *)ptr, count, buffer );
780           break;
781       case FONT_MAGIC:
782           result = FONT_GetObjectW( (FONTOBJ *)ptr, count, buffer );
783
784           /*
785            * Fix the LOGFONT structure for the stock fonts
786            */
787           if ( (handle >= FIRST_STOCK_HANDLE) && 
788                (handle <= LAST_STOCK_HANDLE) )
789             FixStockFontSizeW(handle, count, buffer);
790           break;
791       case PALETTE_MAGIC:
792           result = PALETTE_GetObject( (PALETTEOBJ *)ptr, count, buffer );
793           break;
794       default:
795           FIXME("Magic %04x not implemented\n", GDIMAGIC(ptr->wMagic) );
796           break;
797     }
798     GDI_ReleaseObj( handle );
799     return result;
800 }
801
802 /***********************************************************************
803  *           GetObjectType    (GDI32.@)
804  */
805 DWORD WINAPI GetObjectType( HANDLE handle )
806 {
807     GDIOBJHDR * ptr;
808     INT result = 0;
809     TRACE("%08x\n", handle );
810
811     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
812     
813     switch(GDIMAGIC(ptr->wMagic))
814     {
815       case PEN_MAGIC:
816           result = OBJ_PEN;
817           break;
818       case BRUSH_MAGIC: 
819           result = OBJ_BRUSH;
820           break;
821       case BITMAP_MAGIC: 
822           result = OBJ_BITMAP;
823           break;
824       case FONT_MAGIC:
825           result = OBJ_FONT;
826           break;
827       case PALETTE_MAGIC:
828           result = OBJ_PAL;
829           break;
830       case REGION_MAGIC:
831           result = OBJ_REGION;
832           break;
833       case DC_MAGIC:
834           result = OBJ_DC;
835           break;
836       case META_DC_MAGIC:
837           result = OBJ_METADC;
838           break;
839       case METAFILE_MAGIC:
840           result = OBJ_METAFILE;
841           break;
842       case METAFILE_DC_MAGIC:
843           result = OBJ_METADC;
844           break;
845       case ENHMETAFILE_MAGIC:
846           result = OBJ_ENHMETAFILE;
847           break;
848       case ENHMETAFILE_DC_MAGIC:
849           result = OBJ_ENHMETADC;
850           break;
851       default:
852           FIXME("Magic %04x not implemented\n", GDIMAGIC(ptr->wMagic) );
853           break;
854     }
855     GDI_ReleaseObj( handle );
856     return result;
857 }
858
859 /***********************************************************************
860  *           GetCurrentObject           (GDI32.@)
861  */
862 HANDLE WINAPI GetCurrentObject(HDC hdc,UINT type)
863 {
864     HANDLE ret = 0;
865     DC * dc = DC_GetDCPtr( hdc );
866
867     if (dc) 
868     {
869     switch (type) {
870         case OBJ_PEN:    ret = dc->hPen; break;
871         case OBJ_BRUSH:  ret = dc->hBrush; break;
872         case OBJ_PAL:    ret = dc->hPalette; break;
873         case OBJ_FONT:   ret = dc->hFont; break;
874         case OBJ_BITMAP: ret = dc->hBitmap; break;
875     default:
876         /* the SDK only mentions those above */
877         FIXME("(%08x,%d): unknown type.\n",hdc,type);
878             break;
879         }
880         GDI_ReleaseObj( hdc );
881     }
882     return ret;
883 }
884
885
886 /***********************************************************************
887  *           SelectObject16    (GDI.45)
888  */
889 HGDIOBJ16 WINAPI SelectObject16( HDC16 hdc, HGDIOBJ16 handle )
890 {
891     return (HGDIOBJ16)SelectObject( hdc, handle );
892 }
893
894
895 /***********************************************************************
896  *           SelectObject    (GDI32.@)
897  */
898 HGDIOBJ WINAPI SelectObject( HDC hdc, HGDIOBJ handle )
899 {
900     HGDIOBJ ret = 0;
901     DC * dc = DC_GetDCUpdate( hdc );
902     if (!dc) return 0;
903     TRACE("hdc=%04x %04x\n", hdc, handle );
904     if (dc->funcs->pSelectObject)
905         ret = dc->funcs->pSelectObject( dc, handle );
906     GDI_ReleaseObj( hdc );
907     return ret;
908 }
909
910
911 /***********************************************************************
912  *           UnrealizeObject16    (GDI.150)
913  */
914 BOOL16 WINAPI UnrealizeObject16( HGDIOBJ16 obj )
915 {
916     return UnrealizeObject( obj );
917 }
918
919
920 /***********************************************************************
921  *           UnrealizeObject    (GDI32.@)
922  */
923 BOOL WINAPI UnrealizeObject( HGDIOBJ obj )
924 {
925     BOOL result = TRUE;
926   /* Check if object is valid */
927
928     GDIOBJHDR * header = GDI_GetObjPtr( obj, MAGIC_DONTCARE );
929     if (!header) return FALSE;
930
931     TRACE("%04x\n", obj );
932
933       /* Unrealize object */
934
935     switch(GDIMAGIC(header->wMagic))
936     {
937     case PALETTE_MAGIC: 
938         result = PALETTE_UnrealizeObject( obj, (PALETTEOBJ *)header );
939         break;
940
941     case BRUSH_MAGIC:
942         /* Windows resets the brush origin. We don't need to. */
943         break;
944     }
945     GDI_ReleaseObj( obj );
946     return result;
947 }
948
949
950 /***********************************************************************
951  *           EnumObjects16    (GDI.71)
952  */
953 INT16 WINAPI EnumObjects16( HDC16 hdc, INT16 nObjType,
954                             GOBJENUMPROC16 lpEnumFunc, LPARAM lParam )
955 {
956     /* Solid colors to enumerate */
957     static const COLORREF solid_colors[] =
958     { RGB(0x00,0x00,0x00), RGB(0xff,0xff,0xff),
959       RGB(0xff,0x00,0x00), RGB(0x00,0xff,0x00),
960       RGB(0x00,0x00,0xff), RGB(0xff,0xff,0x00),
961       RGB(0xff,0x00,0xff), RGB(0x00,0xff,0xff),
962       RGB(0x80,0x00,0x00), RGB(0x00,0x80,0x00),
963       RGB(0x80,0x80,0x00), RGB(0x00,0x00,0x80),
964       RGB(0x80,0x00,0x80), RGB(0x00,0x80,0x80),
965       RGB(0x80,0x80,0x80), RGB(0xc0,0xc0,0xc0)
966     };
967     
968     INT16 i, retval = 0;
969     LOGPEN16 *pen;
970     LOGBRUSH16 *brush = NULL;
971
972     TRACE("%04x %d %08lx %08lx\n",
973                  hdc, nObjType, (DWORD)lpEnumFunc, lParam );
974     switch(nObjType)
975     {
976     case OBJ_PEN:
977         /* Enumerate solid pens */
978         if (!(pen = SEGPTR_NEW(LOGPEN16))) break;
979         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
980         {
981             pen->lopnStyle   = PS_SOLID;
982             pen->lopnWidth.x = 1;
983             pen->lopnWidth.y = 0;
984             pen->lopnColor   = solid_colors[i];
985             retval = lpEnumFunc( SEGPTR_GET(pen), lParam );
986             TRACE("solid pen %08lx, ret=%d\n",
987                          solid_colors[i], retval);
988             if (!retval) break;
989         }
990         SEGPTR_FREE(pen);
991         break;
992
993     case OBJ_BRUSH:
994         /* Enumerate solid brushes */
995         if (!(brush = SEGPTR_NEW(LOGBRUSH16))) break;
996         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
997         {
998             brush->lbStyle = BS_SOLID;
999             brush->lbColor = solid_colors[i];
1000             brush->lbHatch = 0;
1001             retval = lpEnumFunc( SEGPTR_GET(brush), lParam );
1002             TRACE("solid brush %08lx, ret=%d\n",
1003                          solid_colors[i], retval);
1004             if (!retval) break;
1005         }
1006
1007         /* Now enumerate hatched brushes */
1008         if (retval) for (i = HS_HORIZONTAL; i <= HS_DIAGCROSS; i++)
1009         {
1010             brush->lbStyle = BS_HATCHED;
1011             brush->lbColor = RGB(0,0,0);
1012             brush->lbHatch = i;
1013             retval = lpEnumFunc( SEGPTR_GET(brush), lParam );
1014             TRACE("hatched brush %d, ret=%d\n",
1015                          i, retval);
1016             if (!retval) break;
1017         }
1018         SEGPTR_FREE(brush);
1019         break;
1020
1021     default:
1022         WARN("(%d): Invalid type\n", nObjType );
1023         break;
1024     }
1025     return retval;
1026 }
1027
1028
1029 /***********************************************************************
1030  *           EnumObjects    (GDI32.@)
1031  */
1032 INT WINAPI EnumObjects( HDC hdc, INT nObjType,
1033                             GOBJENUMPROC lpEnumFunc, LPARAM lParam )
1034 {
1035     /* Solid colors to enumerate */
1036     static const COLORREF solid_colors[] =
1037     { RGB(0x00,0x00,0x00), RGB(0xff,0xff,0xff),
1038       RGB(0xff,0x00,0x00), RGB(0x00,0xff,0x00),
1039       RGB(0x00,0x00,0xff), RGB(0xff,0xff,0x00),
1040       RGB(0xff,0x00,0xff), RGB(0x00,0xff,0xff),
1041       RGB(0x80,0x00,0x00), RGB(0x00,0x80,0x00),
1042       RGB(0x80,0x80,0x00), RGB(0x00,0x00,0x80),
1043       RGB(0x80,0x00,0x80), RGB(0x00,0x80,0x80),
1044       RGB(0x80,0x80,0x80), RGB(0xc0,0xc0,0xc0)
1045     };
1046     
1047     INT i, retval = 0;
1048     LOGPEN pen;
1049     LOGBRUSH brush;
1050
1051     TRACE("%04x %d %08lx %08lx\n",
1052                  hdc, nObjType, (DWORD)lpEnumFunc, lParam );
1053     switch(nObjType)
1054     {
1055     case OBJ_PEN:
1056         /* Enumerate solid pens */
1057         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
1058         {
1059             pen.lopnStyle   = PS_SOLID;
1060             pen.lopnWidth.x = 1;
1061             pen.lopnWidth.y = 0;
1062             pen.lopnColor   = solid_colors[i];
1063             retval = lpEnumFunc( &pen, lParam );
1064             TRACE("solid pen %08lx, ret=%d\n",
1065                          solid_colors[i], retval);
1066             if (!retval) break;
1067         }
1068         break;
1069
1070     case OBJ_BRUSH:
1071         /* Enumerate solid brushes */
1072         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
1073         {
1074             brush.lbStyle = BS_SOLID;
1075             brush.lbColor = solid_colors[i];
1076             brush.lbHatch = 0;
1077             retval = lpEnumFunc( &brush, lParam );
1078             TRACE("solid brush %08lx, ret=%d\n",
1079                          solid_colors[i], retval);
1080             if (!retval) break;
1081         }
1082
1083         /* Now enumerate hatched brushes */
1084         if (retval) for (i = HS_HORIZONTAL; i <= HS_DIAGCROSS; i++)
1085         {
1086             brush.lbStyle = BS_HATCHED;
1087             brush.lbColor = RGB(0,0,0);
1088             brush.lbHatch = i;
1089             retval = lpEnumFunc( &brush, lParam );
1090             TRACE("hatched brush %d, ret=%d\n",
1091                          i, retval);
1092             if (!retval) break;
1093         }
1094         break;
1095
1096     default:
1097         /* FIXME: implement Win32 types */
1098         WARN("(%d): Invalid type\n", nObjType );
1099         break;
1100     }
1101     return retval;
1102 }
1103
1104
1105 /***********************************************************************
1106  *           IsGDIObject    (GDI.462)
1107  * 
1108  * returns type of object if valid (W95 system programming secrets p. 264-5)
1109  */
1110 BOOL16 WINAPI IsGDIObject16( HGDIOBJ16 handle )
1111 {
1112     UINT16 magic = 0;
1113
1114     GDIOBJHDR *object = GDI_GetObjPtr( handle, MAGIC_DONTCARE );
1115     if (object)
1116     {
1117         magic = GDIMAGIC(object->wMagic) - PEN_MAGIC + 1;
1118         GDI_ReleaseObj( handle );
1119     }
1120     return magic;
1121 }
1122
1123
1124 /***********************************************************************
1125  *           SetObjectOwner16    (GDI.461)
1126  */
1127 void WINAPI SetObjectOwner16( HGDIOBJ16 handle, HANDLE16 owner )
1128 {
1129     /* Nothing to do */
1130 }
1131
1132
1133 /***********************************************************************
1134  *           SetObjectOwner    (GDI32.@)
1135  */
1136 void WINAPI SetObjectOwner( HGDIOBJ handle, HANDLE owner )
1137 {
1138     /* Nothing to do */
1139 }
1140
1141
1142 /***********************************************************************
1143  *           MakeObjectPrivate    (GDI.463)
1144  *
1145  * What does that mean ?
1146  * Some little docu can be found in "Undocumented Windows",
1147  * but this is basically useless.
1148  * At least we know that this flags the GDI object's wMagic
1149  * with 0x2000 (OBJECT_PRIVATE), so we just do it.
1150  * But Wine doesn't react on that yet.
1151  */
1152 void WINAPI MakeObjectPrivate16( HGDIOBJ16 handle, BOOL16 private )
1153 {
1154     GDIOBJHDR *ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE );
1155     if (!ptr)
1156     {
1157         ERR("invalid GDI object %04x !\n", handle);
1158         return;
1159     }
1160     ptr->wMagic |= OBJECT_PRIVATE;
1161     GDI_ReleaseObj( handle );
1162 }
1163
1164
1165 /***********************************************************************
1166  *           GdiFlush    (GDI32.@)
1167  */
1168 BOOL WINAPI GdiFlush(void)
1169 {
1170     return TRUE;  /* FIXME */
1171 }
1172
1173
1174 /***********************************************************************
1175  *           GdiGetBatchLimit    (GDI32.@)
1176  */
1177 DWORD WINAPI GdiGetBatchLimit(void)
1178 {
1179     return 1;  /* FIXME */
1180 }
1181
1182
1183 /***********************************************************************
1184  *           GdiSetBatchLimit    (GDI32.@)
1185  */
1186 DWORD WINAPI GdiSetBatchLimit( DWORD limit )
1187 {
1188     return 1; /* FIXME */
1189 }
1190
1191
1192 /***********************************************************************
1193  *           GdiSeeGdiDo   (GDI.452)
1194  */
1195 DWORD WINAPI GdiSeeGdiDo16( WORD wReqType, WORD wParam1, WORD wParam2,
1196                           WORD wParam3 )
1197 {
1198     switch (wReqType)
1199     {
1200     case 0x0001:  /* LocalAlloc */
1201         return LOCAL_Alloc( GDI_HeapSel, wParam1, wParam3 );
1202     case 0x0002:  /* LocalFree */
1203         return LOCAL_Free( GDI_HeapSel, wParam1 );
1204     case 0x0003:  /* LocalCompact */
1205         return LOCAL_Compact( GDI_HeapSel, wParam3, 0 );
1206     case 0x0103:  /* LocalHeap */
1207         return GDI_HeapSel;
1208     default:
1209         WARN("(wReqType=%04x): Unknown\n", wReqType);
1210         return (DWORD)-1;
1211     }
1212 }
1213
1214 /***********************************************************************
1215  *           GdiSignalProc     (GDI.610)
1216  */
1217 WORD WINAPI GdiSignalProc( UINT uCode, DWORD dwThreadOrProcessID,
1218                            DWORD dwFlags, HMODULE16 hModule )
1219 {
1220     return 0;
1221 }
1222
1223 /***********************************************************************
1224  *           FinalGdiInit16     (GDI.405)
1225  */
1226 void WINAPI FinalGdiInit16( HANDLE16 unknown )
1227 {
1228 }
1229
1230 /***********************************************************************
1231  *           GdiFreeResources   (GDI.609)
1232  */
1233 WORD WINAPI GdiFreeResources16( DWORD reserve )
1234 {
1235    return (WORD)( (int)LOCAL_CountFree( GDI_HeapSel ) * 100 /
1236                   (int)LOCAL_HeapSize( GDI_HeapSel ) );
1237 }
1238
1239 /***********************************************************************
1240  *           MulDiv16   (GDI.128)
1241  */
1242 INT16 WINAPI MulDiv16(
1243              INT16 nMultiplicand, 
1244              INT16 nMultiplier,
1245              INT16 nDivisor)
1246 {
1247     INT ret;
1248     if (!nDivisor) return -32768;
1249     /* We want to deal with a positive divisor to simplify the logic. */
1250     if (nDivisor < 0)
1251     {
1252       nMultiplicand = - nMultiplicand;
1253       nDivisor = -nDivisor;
1254     }
1255     /* If the result is positive, we "add" to round. else, 
1256      * we subtract to round. */
1257     if ( ( (nMultiplicand <  0) && (nMultiplier <  0) ) ||
1258          ( (nMultiplicand >= 0) && (nMultiplier >= 0) ) )
1259         ret = (((int)nMultiplicand * nMultiplier) + (nDivisor/2)) / nDivisor;
1260     else
1261         ret = (((int)nMultiplicand * nMultiplier) - (nDivisor/2)) / nDivisor;
1262     if ((ret > 32767) || (ret < -32767)) return -32768;
1263     return (INT16) ret;
1264 }
1265
1266
1267 /*******************************************************************
1268  *      GetColorAdjustment [GDI32.@]
1269  *
1270  *
1271  */
1272 BOOL WINAPI GetColorAdjustment(HDC hdc, LPCOLORADJUSTMENT lpca)
1273 {
1274         FIXME("GetColorAdjustment, stub\n");
1275         return 0;
1276 }
1277
1278 /*******************************************************************
1279  *      GetMiterLimit [GDI32.@]
1280  *
1281  *
1282  */
1283 BOOL WINAPI GetMiterLimit(HDC hdc, PFLOAT peLimit)
1284 {
1285         FIXME("GetMiterLimit, stub\n");
1286         return 0;
1287 }
1288
1289 /*******************************************************************
1290  *      SetMiterLimit [GDI32.@]
1291  *
1292  *
1293  */
1294 BOOL WINAPI SetMiterLimit(HDC hdc, FLOAT eNewLimit, PFLOAT peOldLimit)
1295 {
1296         FIXME("SetMiterLimit, stub\n");
1297         return 0;
1298 }
1299
1300 /*******************************************************************
1301  *      GdiComment [GDI32.@]
1302  *
1303  *
1304  */
1305 BOOL WINAPI GdiComment(HDC hdc, UINT cbSize, const BYTE *lpData)
1306 {
1307         FIXME("GdiComment, stub\n");
1308         return 0;
1309 }
1310 /*******************************************************************
1311  *      SetColorAdjustment [GDI32.@]
1312  *
1313  *
1314  */
1315 BOOL WINAPI SetColorAdjustment(HDC hdc, const COLORADJUSTMENT* lpca)
1316 {
1317         FIXME("SetColorAdjustment, stub\n");
1318         return 0;
1319 }
1320