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