Fixed bug in DIB_SetImageBits_RLE8 (because 'color' var was WORD, all
[wine] / objects / gdiobj.c
1 /*
2  * GDI functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 #include <stdlib.h>
8 #include "color.h"
9 #include "bitmap.h"
10 #include "brush.h"
11 #include "dc.h"
12 #include "font.h"
13 #include "heap.h"
14 #include "options.h"
15 #include "palette.h"
16 #include "pen.h"
17 #include "region.h"
18 #include "debug.h"
19 #include "gdi.h"
20
21
22 /***********************************************************************
23  *          GDI stock objects 
24  */
25
26 static BRUSHOBJ WhiteBrush =
27 {
28     { 0, BRUSH_MAGIC, 1 },             /* header */
29     { BS_SOLID, RGB(255,255,255), 0 }  /* logbrush */
30 };
31
32 static BRUSHOBJ LtGrayBrush =
33 {
34     { 0, BRUSH_MAGIC, 1 },             /* header */
35 /* FIXME : this should perhaps be BS_HATCHED, at least for 1 bitperpixel */
36     { BS_SOLID, RGB(192,192,192), 0 }  /* logbrush */
37 };
38
39 static BRUSHOBJ GrayBrush =
40 {
41     { 0, BRUSH_MAGIC, 1 },             /* header */
42 /* FIXME : this should perhaps be BS_HATCHED, at least for 1 bitperpixel */
43     { BS_SOLID, RGB(128,128,128), 0 }  /* logbrush */
44 };
45
46 static BRUSHOBJ DkGrayBrush =
47 {
48     { 0, BRUSH_MAGIC, 1 },          /* header */
49 /* This is BS_HATCHED, for 1 bitperpixel. This makes the spray work in pbrush */
50 /* NB_HATCH_STYLES is an index into HatchBrushes */
51     { BS_HATCHED, RGB(0,0,0), NB_HATCH_STYLES }  /* logbrush */
52 };
53
54 static BRUSHOBJ BlackBrush =
55 {
56     { 0, BRUSH_MAGIC, 1 },       /* header */
57     { BS_SOLID, RGB(0,0,0), 0 }  /* logbrush */
58 };
59
60 static BRUSHOBJ NullBrush =
61 {
62     { 0, BRUSH_MAGIC, 1 },  /* header */
63     { BS_NULL, 0, 0 }       /* logbrush */
64 };
65
66 static PENOBJ WhitePen =
67 {
68     { 0, PEN_MAGIC, 1 },                     /* header */
69     { PS_SOLID, { 1, 0 }, RGB(255,255,255) } /* logpen */
70 };
71
72 static PENOBJ BlackPen =
73 {
74     { 0, PEN_MAGIC, 1 },               /* header */
75     { PS_SOLID, { 1, 0 }, RGB(0,0,0) } /* logpen */
76 };
77
78 static PENOBJ NullPen =
79 {
80     { 0, PEN_MAGIC, 1 },      /* header */
81     { PS_NULL, { 1, 0 }, 0 }  /* logpen */
82 };
83
84 static FONTOBJ OEMFixedFont =
85 {
86     { 0, FONT_MAGIC, 1 },   /* header */
87     { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, OEM_CHARSET,
88       0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, "" }
89 };
90 /* Filler to make the location counter dword aligned again.  This is necessary
91    since (a) FONTOBJ is packed, (b) gcc places initialised variables in the code
92    segment, and (c) Solaris assembler is stupid.  */
93 static UINT16 align_OEMFixedFont = 1;
94
95 static FONTOBJ AnsiFixedFont =
96 {
97     { 0, FONT_MAGIC, 1 },   /* header */
98     { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
99       0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, "" }
100 };
101 static UINT16 align_AnsiFixedFont = 1;
102
103 static FONTOBJ AnsiVarFont =
104 {
105     { 0, FONT_MAGIC, 1 },   /* header */
106     { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
107       0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, "MS Sans Serif" }
108 };
109 static UINT16 align_AnsiVarFont = 1;
110
111 static FONTOBJ SystemFont =
112 {
113     { 0, FONT_MAGIC, 1 },
114     { 16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET,
115       0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, "System" }
116 };
117 static UINT16 align_SystemFont = 1;
118
119 static FONTOBJ DeviceDefaultFont =
120 {
121     { 0, FONT_MAGIC, 1 },   /* header */
122     { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
123       0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, "" }
124 };
125 static UINT16 align_DeviceDefaultFont = 1;
126
127 static FONTOBJ SystemFixedFont =
128 {
129     { 0, FONT_MAGIC, 1 },   /* header */
130     { 12, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET,
131       0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, "" }
132 };
133 static UINT16 align_SystemFixedFont = 1;
134
135 /* FIXME: Is this correct? */
136 static FONTOBJ DefaultGuiFont =
137 {
138     { 9, FONT_MAGIC, 1 },   /* header */
139     { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
140       0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, "MS Sans Serif" }
141 };
142 static UINT16 align_DefaultGuiFont = 1;
143
144
145 static GDIOBJHDR * StockObjects[NB_STOCK_OBJECTS] =
146 {
147     (GDIOBJHDR *) &WhiteBrush,
148     (GDIOBJHDR *) &LtGrayBrush,
149     (GDIOBJHDR *) &GrayBrush,
150     (GDIOBJHDR *) &DkGrayBrush,
151     (GDIOBJHDR *) &BlackBrush,
152     (GDIOBJHDR *) &NullBrush,
153     (GDIOBJHDR *) &WhitePen,
154     (GDIOBJHDR *) &BlackPen,
155     (GDIOBJHDR *) &NullPen,
156     NULL,
157     (GDIOBJHDR *) &OEMFixedFont,
158     (GDIOBJHDR *) &AnsiFixedFont,
159     (GDIOBJHDR *) &AnsiVarFont,
160     (GDIOBJHDR *) &SystemFont,
161     (GDIOBJHDR *) &DeviceDefaultFont,
162     NULL,            /* DEFAULT_PALETTE created by PALETTE_Init */
163     (GDIOBJHDR *) &SystemFixedFont,
164     (GDIOBJHDR *) &DefaultGuiFont
165 };
166
167 /******************************************************************************
168  *
169  *   void  ReadFontInformation(
170  *      char const  *fontName,
171  *      FONTOBJ  *font,
172  *      int  defHeight,
173  *      int  defBold,
174  *      int  defItalic,
175  *      int  defUnderline,
176  *      int  defStrikeOut )
177  *
178  *   ReadFontInformation() checks the Wine configuration file's Tweak.Fonts
179  *   section for entries containing fontName.Height, fontName.Bold, etc.,
180  *   where fontName is the name specified in the call (e.g., "System").  It
181  *   attempts to be user friendly by accepting 'n', 'N', 'f', 'F', or '0' as
182  *   the first character in the boolean attributes (bold, italic, and
183  *   underline).
184  *****************************************************************************/
185
186 static void  ReadFontInformation(
187     char const *fontName,
188     FONTOBJ *font,
189     int  defHeight,
190     int  defBold,
191     int  defItalic,
192     int  defUnderline,
193     int  defStrikeOut )
194 {
195     char  key[256];
196
197     sprintf(key, "%s.Height", fontName);
198     font->logfont.lfHeight =
199         PROFILE_GetWineIniInt("Tweak.Fonts", key, defHeight);
200
201     sprintf(key, "%s.Bold", fontName);
202     font->logfont.lfWeight =
203         (PROFILE_GetWineIniBool("Tweak.Fonts", key, defBold)) ?
204         FW_BOLD : FW_NORMAL;
205
206     sprintf(key, "%s.Italic", fontName);
207     font->logfont.lfItalic =
208         PROFILE_GetWineIniBool("Tweak.Fonts", key, defItalic);
209
210     sprintf(key, "%s.Underline", fontName);
211     font->logfont.lfUnderline =
212         PROFILE_GetWineIniBool("Tweak.Fonts", key, defUnderline);
213
214     sprintf(key, "%s.StrikeOut", fontName);
215     font->logfont.lfStrikeOut =
216         PROFILE_GetWineIniBool("Tweak.Fonts", key, defStrikeOut);
217
218     return;
219 }
220
221
222 /***********************************************************************
223  *           GDI_Init
224  *
225  * GDI initialization.
226  */
227 BOOL32 GDI_Init(void)
228 {
229     /* Kill some warnings.  */
230     (void)align_OEMFixedFont;
231     (void)align_AnsiFixedFont;
232     (void)align_AnsiVarFont;
233     (void)align_SystemFont;
234     (void)align_DeviceDefaultFont;
235     (void)align_SystemFixedFont;
236     (void)align_DefaultGuiFont;
237
238     /* TWEAK: Initialize font hints */
239     ReadFontInformation("OEMFixed", &OEMFixedFont, 12, 0, 0, 0, 0);
240     ReadFontInformation("AnsiFixed", &AnsiFixedFont, 12, 0, 0, 0, 0);
241     ReadFontInformation("AnsiVar", &AnsiVarFont, 12, 0, 0, 0, 0);
242     ReadFontInformation("System", &SystemFont, 16, 1, 0, 0, 0);
243     ReadFontInformation("SystemFixed", &SystemFixedFont, 12, 1, 0, 0, 0);
244
245     /* Initialize drivers */
246
247     DIB_Init(); /* always before X11DRV_Init() */
248
249     if( ! X11DRV_Init() )
250         return FALSE;
251
252         /* Create default palette */
253
254       /* DR well *this* palette can't be moveable (?) */
255     {
256     HPALETTE16 hpalette = PALETTE_Init();
257     if( !hpalette )
258         return FALSE;
259     StockObjects[DEFAULT_PALETTE] = (GDIOBJHDR *)GDI_HEAP_LOCK( hpalette );
260     }
261
262     return TRUE;
263 }
264
265
266 /***********************************************************************
267  *           GDI_AllocObject
268  */
269 HGDIOBJ16 GDI_AllocObject( WORD size, WORD magic )
270 {
271     static DWORD count = 0;
272     GDIOBJHDR * obj;
273     HGDIOBJ16 handle;
274     if ( magic == DC_MAGIC || magic == METAFILE_DC_MAGIC )
275       handle = GDI_HEAP_ALLOC( size );
276     else 
277       handle = GDI_HEAP_ALLOC_MOVEABLE( size );
278     if (!handle) return 0;
279     obj = (GDIOBJHDR *) GDI_HEAP_LOCK( handle );
280     obj->hNext   = 0;
281     obj->wMagic  = magic;
282     obj->dwCount = ++count;
283     GDI_HEAP_UNLOCK( handle );
284     return handle;
285 }
286
287
288 /***********************************************************************
289  *           GDI_FreeObject
290  */
291 BOOL32 GDI_FreeObject( HGDIOBJ16 handle )
292 {
293     GDIOBJHDR * object;
294
295       /* Can't free stock objects */
296     if ((handle >= FIRST_STOCK_HANDLE) && (handle <= LAST_STOCK_HANDLE))
297         return TRUE;
298     
299     object = (GDIOBJHDR *) GDI_HEAP_LOCK( handle );
300     if (!object) return FALSE;
301     object->wMagic = 0;  /* Mark it as invalid */
302  
303       /* Free object */
304     
305     GDI_HEAP_FREE( handle );
306     return TRUE;
307 }
308
309 /***********************************************************************
310  *           GDI_GetObjPtr
311  *
312  * Return a pointer to the GDI object associated to the handle.
313  * Return NULL if the object has the wrong magic number.
314  * Movable GDI objects are locked in memory: it is up to the caller to unlock
315  * it after the caller is done with the pointer.
316  */
317 GDIOBJHDR * GDI_GetObjPtr( HGDIOBJ16 handle, WORD magic )
318 {
319     GDIOBJHDR * ptr = NULL;
320
321     if ((handle >= FIRST_STOCK_HANDLE) && (handle <= LAST_STOCK_HANDLE))
322       ptr = StockObjects[handle - FIRST_STOCK_HANDLE];
323     else 
324       ptr = (GDIOBJHDR *) GDI_HEAP_LOCK( handle );
325     if (!ptr) return NULL;
326     if ((magic != MAGIC_DONTCARE) && (ptr->wMagic != magic)) 
327     {
328       GDI_HEAP_UNLOCK( handle );
329       return NULL;
330     }
331     return ptr;
332 }
333
334
335 /***********************************************************************
336  *           DeleteObject16    (GDI.69)
337  */
338 BOOL16 WINAPI DeleteObject16( HGDIOBJ16 obj )
339 {
340     return DeleteObject32( obj );
341 }
342
343
344 /***********************************************************************
345  *           DeleteObject32    (GDI32.70)
346  */
347 BOOL32 WINAPI DeleteObject32( HGDIOBJ32 obj )
348 {
349       /* Check if object is valid */
350
351     GDIOBJHDR * header;
352     if (HIWORD(obj)) return FALSE;
353     if ((obj >= FIRST_STOCK_HANDLE) && (obj <= LAST_STOCK_HANDLE))
354         return TRUE;
355     if (!(header = (GDIOBJHDR *) GDI_HEAP_LOCK( obj ))) return FALSE;
356
357     TRACE(gdi, "%04x\n", obj );
358
359       /* Delete object */
360
361     switch(header->wMagic)
362     {
363       case PEN_MAGIC:     return GDI_FreeObject( obj );
364       case BRUSH_MAGIC:   return BRUSH_DeleteObject( obj, (BRUSHOBJ*)header );
365       case FONT_MAGIC:    return GDI_FreeObject( obj );
366       case PALETTE_MAGIC: return PALETTE_DeleteObject(obj,(PALETTEOBJ*)header);
367       case BITMAP_MAGIC:  return BITMAP_DeleteObject( obj, (BITMAPOBJ*)header);
368       case REGION_MAGIC:  return REGION_DeleteObject( obj, (RGNOBJ*)header );
369       case DC_MAGIC:      return DeleteDC32(obj);
370       case 0 :
371         WARN(gdi, "Already deleted\n");
372         break;
373       default:
374         WARN(gdi, "Unknown magic number (%d)\n",header->wMagic);
375     }
376     return FALSE;
377 }
378
379 /***********************************************************************
380  *           GetStockObject16    (GDI.87)
381  */
382 HGDIOBJ16 WINAPI GetStockObject16( INT16 obj )
383 {
384     return (HGDIOBJ16)GetStockObject32( obj );
385 }
386
387
388 /***********************************************************************
389  *           GetStockObject32    (GDI32.220)
390  */
391 HGDIOBJ32 WINAPI GetStockObject32( INT32 obj )
392 {
393     if ((obj < 0) || (obj >= NB_STOCK_OBJECTS)) return 0;
394     if (!StockObjects[obj]) return 0;
395     TRACE(gdi, "returning %d\n",
396                 FIRST_STOCK_HANDLE + obj );
397     return (HGDIOBJ16)(FIRST_STOCK_HANDLE + obj);
398 }
399
400
401 /***********************************************************************
402  *           GetObject16    (GDI.82)
403  */
404 INT16 WINAPI GetObject16( HANDLE16 handle, INT16 count, LPVOID buffer )
405 {
406     GDIOBJHDR * ptr = NULL;
407     INT16 result = 0;
408     TRACE(gdi, "%04x %d %p\n", handle, count, buffer );
409     if (!count) return 0;
410
411     if ((handle >= FIRST_STOCK_HANDLE) && (handle <= LAST_STOCK_HANDLE))
412       ptr = StockObjects[handle - FIRST_STOCK_HANDLE];
413     else
414       ptr = (GDIOBJHDR *) GDI_HEAP_LOCK( handle );
415     if (!ptr) return 0;
416     
417     switch(ptr->wMagic)
418       {
419       case PEN_MAGIC:
420         result = PEN_GetObject16( (PENOBJ *)ptr, count, buffer );
421         break;
422       case BRUSH_MAGIC: 
423         result = BRUSH_GetObject16( (BRUSHOBJ *)ptr, count, buffer );
424         break;
425       case BITMAP_MAGIC: 
426         result = BITMAP_GetObject16( (BITMAPOBJ *)ptr, count, buffer );
427         break;
428       case FONT_MAGIC:
429         result = FONT_GetObject16( (FONTOBJ *)ptr, count, buffer );
430         break;
431       case PALETTE_MAGIC:
432         result = PALETTE_GetObject( (PALETTEOBJ *)ptr, count, buffer );
433         break;
434       }
435     GDI_HEAP_UNLOCK( handle );
436     return result;
437 }
438
439
440 /***********************************************************************
441  *           GetObject32A    (GDI32.204)
442  */
443 INT32 WINAPI GetObject32A( HANDLE32 handle, INT32 count, LPVOID buffer )
444 {
445     GDIOBJHDR * ptr = NULL;
446     INT32 result = 0;
447     TRACE(gdi, "%08x %d %p\n", handle, count, buffer );
448     if (!count) return 0;
449
450     if ((handle >= FIRST_STOCK_HANDLE) && (handle <= LAST_STOCK_HANDLE))
451       ptr = StockObjects[handle - FIRST_STOCK_HANDLE];
452     else
453       ptr = (GDIOBJHDR *) GDI_HEAP_LOCK( handle );
454     if (!ptr) return 0;
455     
456     switch(ptr->wMagic)
457     {
458       case PEN_MAGIC:
459           result = PEN_GetObject32( (PENOBJ *)ptr, count, buffer );
460           break;
461       case BRUSH_MAGIC: 
462           result = BRUSH_GetObject32( (BRUSHOBJ *)ptr, count, buffer );
463           break;
464       case BITMAP_MAGIC: 
465           result = BITMAP_GetObject32( (BITMAPOBJ *)ptr, count, buffer );
466           break;
467       case FONT_MAGIC:
468           result = FONT_GetObject32A( (FONTOBJ *)ptr, count, buffer );
469           break;
470       case PALETTE_MAGIC:
471           result = PALETTE_GetObject( (PALETTEOBJ *)ptr, count, buffer );
472           break;
473       default:
474           FIXME(gdi, "Magic %04x not implemented\n",
475                    ptr->wMagic );
476           break;
477     }
478     GDI_HEAP_UNLOCK( handle );
479     return result;
480 }
481
482 /***********************************************************************
483  *           GetObjectType    (GDI32.205)
484  */
485 DWORD WINAPI GetObjectType( HANDLE32 handle )
486 {
487     GDIOBJHDR * ptr = NULL;
488     INT32 result = 0;
489     TRACE(gdi, "%08x\n", handle );
490
491     if ((handle >= FIRST_STOCK_HANDLE) && (handle <= LAST_STOCK_HANDLE))
492       ptr = StockObjects[handle - FIRST_STOCK_HANDLE];
493     else
494       ptr = (GDIOBJHDR *) GDI_HEAP_LOCK( handle );
495     if (!ptr) return 0;
496     
497     switch(ptr->wMagic)
498     {
499       case PEN_MAGIC:
500           result = OBJ_PEN;
501           break;
502       case BRUSH_MAGIC: 
503           result = OBJ_BRUSH;
504           break;
505       case BITMAP_MAGIC: 
506           result = OBJ_BITMAP;
507           break;
508       case FONT_MAGIC:
509           result = OBJ_FONT;
510           break;
511       case PALETTE_MAGIC:
512           result = OBJ_PAL;
513           break;
514       case REGION_MAGIC:
515           result = OBJ_REGION;
516           break;
517       case DC_MAGIC:
518           result = OBJ_DC;
519           break;
520       case META_DC_MAGIC:
521           result = OBJ_METADC;
522           break;
523       case METAFILE_MAGIC:
524           result = OBJ_METAFILE;
525           break;
526       case METAFILE_DC_MAGIC:
527           result = OBJ_METADC;
528           break;
529
530       default:
531           FIXME(gdi, "Magic %04x not implemented\n",
532                            ptr->wMagic );
533           break;
534     }
535     GDI_HEAP_UNLOCK( handle );
536     return result;
537 }
538
539 /***********************************************************************
540  *           GetObject32W    (GDI32.206)
541  */
542 INT32 WINAPI GetObject32W( HANDLE32 handle, INT32 count, LPVOID buffer )
543 {
544     return GetObject32A( handle, count, buffer );
545 }
546
547 /***********************************************************************
548  *           GetCurrentObject           (GDI32.166)
549  */
550 HANDLE32 WINAPI GetCurrentObject(HDC32 hdc,UINT32 type)
551 {
552     DC * dc = DC_GetDCPtr( hdc );
553
554     if (!dc) 
555         return 0;
556     switch (type) {
557     case OBJ_PEN:       return dc->w.hPen;
558     case OBJ_BRUSH:     return dc->w.hBrush;
559     case OBJ_PAL:       return dc->w.hPalette;
560     case OBJ_FONT:      return dc->w.hFont;
561     case OBJ_BITMAP:    return dc->w.hBitmap;
562     default:
563         /* the SDK only mentions those above */
564         WARN(gdi,"(%08x,%d): unknown type.\n",hdc,type);
565         return 0;
566     }
567 }
568
569
570 /***********************************************************************
571  *           SelectObject16    (GDI.45)
572  */
573 HGDIOBJ16 WINAPI SelectObject16( HDC16 hdc, HGDIOBJ16 handle )
574 {
575     return (HGDIOBJ16)SelectObject32( hdc, handle );
576 }
577
578
579 /***********************************************************************
580  *           SelectObject32    (GDI32.299)
581  */
582 HGDIOBJ32 WINAPI SelectObject32( HDC32 hdc, HGDIOBJ32 handle )
583 {
584     DC * dc = DC_GetDCPtr( hdc );
585     if (!dc || !dc->funcs->pSelectObject) return 0;
586     TRACE(gdi, "hdc=%04x %04x\n", hdc, handle );
587     return dc->funcs->pSelectObject( dc, handle );
588 }
589
590
591 /***********************************************************************
592  *           UnrealizeObject16    (GDI.150)
593  */
594 BOOL16 WINAPI UnrealizeObject16( HGDIOBJ16 obj )
595 {
596     return UnrealizeObject32( obj );
597 }
598
599
600 /***********************************************************************
601  *           UnrealizeObject    (GDI32.358)
602  */
603 BOOL32 WINAPI UnrealizeObject32( HGDIOBJ32 obj )
604 {
605     BOOL32 result = TRUE;
606   /* Check if object is valid */
607
608     GDIOBJHDR * header = (GDIOBJHDR *) GDI_HEAP_LOCK( obj );
609     if (!header) return FALSE;
610
611     TRACE(gdi, "%04x\n", obj );
612
613       /* Unrealize object */
614
615     switch(header->wMagic)
616     {
617     case PALETTE_MAGIC: 
618         result = PALETTE_UnrealizeObject( obj, (PALETTEOBJ *)header );
619         break;
620
621     case BRUSH_MAGIC:
622         /* Windows resets the brush origin. We don't need to. */
623         break;
624     }
625     GDI_HEAP_UNLOCK( obj );
626     return result;
627 }
628
629
630 /***********************************************************************
631  *           EnumObjects16    (GDI.71)
632  */
633 INT16 WINAPI EnumObjects16( HDC16 hdc, INT16 nObjType,
634                             GOBJENUMPROC16 lpEnumFunc, LPARAM lParam )
635 {
636     /* Solid colors to enumerate */
637     static const COLORREF solid_colors[] =
638     { RGB(0x00,0x00,0x00), RGB(0xff,0xff,0xff),
639       RGB(0xff,0x00,0x00), RGB(0x00,0xff,0x00),
640       RGB(0x00,0x00,0xff), RGB(0xff,0xff,0x00),
641       RGB(0xff,0x00,0xff), RGB(0x00,0xff,0xff),
642       RGB(0x80,0x00,0x00), RGB(0x00,0x80,0x00),
643       RGB(0x80,0x80,0x00), RGB(0x00,0x00,0x80),
644       RGB(0x80,0x00,0x80), RGB(0x00,0x80,0x80),
645       RGB(0x80,0x80,0x80), RGB(0xc0,0xc0,0xc0)
646     };
647     
648     INT16 i, retval = 0;
649     LOGPEN16 *pen;
650     LOGBRUSH16 *brush = NULL;
651
652     TRACE(gdi, "%04x %d %08lx %08lx\n",
653                  hdc, nObjType, (DWORD)lpEnumFunc, lParam );
654     switch(nObjType)
655     {
656     case OBJ_PEN:
657         /* Enumerate solid pens */
658         if (!(pen = SEGPTR_NEW(LOGPEN16))) break;
659         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
660         {
661             pen->lopnStyle   = PS_SOLID;
662             pen->lopnWidth.x = 1;
663             pen->lopnWidth.y = 0;
664             pen->lopnColor   = solid_colors[i];
665             retval = lpEnumFunc( SEGPTR_GET(pen), lParam );
666             TRACE(gdi, "solid pen %08lx, ret=%d\n",
667                          solid_colors[i], retval);
668             if (!retval) break;
669         }
670         SEGPTR_FREE(pen);
671         break;
672
673     case OBJ_BRUSH:
674         /* Enumerate solid brushes */
675         if (!(brush = SEGPTR_NEW(LOGBRUSH16))) break;
676         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
677         {
678             brush->lbStyle = BS_SOLID;
679             brush->lbColor = solid_colors[i];
680             brush->lbHatch = 0;
681             retval = lpEnumFunc( SEGPTR_GET(brush), lParam );
682             TRACE(gdi, "solid brush %08lx, ret=%d\n",
683                          solid_colors[i], retval);
684             if (!retval) break;
685         }
686
687         /* Now enumerate hatched brushes */
688         if (retval) for (i = HS_HORIZONTAL; i <= HS_DIAGCROSS; i++)
689         {
690             brush->lbStyle = BS_HATCHED;
691             brush->lbColor = RGB(0,0,0);
692             brush->lbHatch = i;
693             retval = lpEnumFunc( SEGPTR_GET(brush), lParam );
694             TRACE(gdi, "hatched brush %d, ret=%d\n",
695                          i, retval);
696             if (!retval) break;
697         }
698         SEGPTR_FREE(brush);
699         break;
700
701     default:
702         WARN(gdi, "(%d): Invalid type\n", nObjType );
703         break;
704     }
705     return retval;
706 }
707
708
709 /***********************************************************************
710  *           EnumObjects32    (GDI32.89)
711  */
712 INT32 WINAPI EnumObjects32( HDC32 hdc, INT32 nObjType,
713                             GOBJENUMPROC32 lpEnumFunc, LPARAM lParam )
714 {
715     /* Solid colors to enumerate */
716     static const COLORREF solid_colors[] =
717     { RGB(0x00,0x00,0x00), RGB(0xff,0xff,0xff),
718       RGB(0xff,0x00,0x00), RGB(0x00,0xff,0x00),
719       RGB(0x00,0x00,0xff), RGB(0xff,0xff,0x00),
720       RGB(0xff,0x00,0xff), RGB(0x00,0xff,0xff),
721       RGB(0x80,0x00,0x00), RGB(0x00,0x80,0x00),
722       RGB(0x80,0x80,0x00), RGB(0x00,0x00,0x80),
723       RGB(0x80,0x00,0x80), RGB(0x00,0x80,0x80),
724       RGB(0x80,0x80,0x80), RGB(0xc0,0xc0,0xc0)
725     };
726     
727     INT32 i, retval = 0;
728     LOGPEN32 pen;
729     LOGBRUSH32 brush;
730
731     TRACE(gdi, "%04x %d %08lx %08lx\n",
732                  hdc, nObjType, (DWORD)lpEnumFunc, lParam );
733     switch(nObjType)
734     {
735     case OBJ_PEN:
736         /* Enumerate solid pens */
737         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
738         {
739             pen.lopnStyle   = PS_SOLID;
740             pen.lopnWidth.x = 1;
741             pen.lopnWidth.y = 0;
742             pen.lopnColor   = solid_colors[i];
743             retval = lpEnumFunc( &pen, lParam );
744             TRACE(gdi, "solid pen %08lx, ret=%d\n",
745                          solid_colors[i], retval);
746             if (!retval) break;
747         }
748         break;
749
750     case OBJ_BRUSH:
751         /* Enumerate solid brushes */
752         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
753         {
754             brush.lbStyle = BS_SOLID;
755             brush.lbColor = solid_colors[i];
756             brush.lbHatch = 0;
757             retval = lpEnumFunc( &brush, lParam );
758             TRACE(gdi, "solid brush %08lx, ret=%d\n",
759                          solid_colors[i], retval);
760             if (!retval) break;
761         }
762
763         /* Now enumerate hatched brushes */
764         if (retval) for (i = HS_HORIZONTAL; i <= HS_DIAGCROSS; i++)
765         {
766             brush.lbStyle = BS_HATCHED;
767             brush.lbColor = RGB(0,0,0);
768             brush.lbHatch = i;
769             retval = lpEnumFunc( &brush, lParam );
770             TRACE(gdi, "hatched brush %d, ret=%d\n",
771                          i, retval);
772             if (!retval) break;
773         }
774         break;
775
776     default:
777         /* FIXME: implement Win32 types */
778         WARN( gdi, "(%d): Invalid type\n", nObjType );
779         break;
780     }
781     return retval;
782 }
783
784
785 /***********************************************************************
786  *           IsGDIObject    (GDI.462)
787  * 
788  * returns type of object if valid (W95 system programming secrets p. 264-5)
789  */
790 BOOL16 WINAPI IsGDIObject( HGDIOBJ16 handle )
791 {
792     UINT16 magic = 0;
793
794     if (handle >= FIRST_STOCK_HANDLE ) 
795     {
796         switch (handle)
797         {
798         case STOCK_WHITE_BRUSH:
799         case STOCK_LTGRAY_BRUSH:
800         case STOCK_GRAY_BRUSH:
801         case STOCK_DKGRAY_BRUSH:
802         case STOCK_BLACK_BRUSH:
803         case STOCK_HOLLOW_BRUSH:
804             magic = BRUSH_MAGIC;
805             break;
806
807         case STOCK_WHITE_PEN:
808         case STOCK_BLACK_PEN:
809         case STOCK_NULL_PEN :
810             magic = PEN_MAGIC;
811             break;
812
813         case STOCK_OEM_FIXED_FONT:
814         case STOCK_ANSI_FIXED_FONT:
815         case STOCK_ANSI_VAR_FONT:
816         case STOCK_SYSTEM_FONT:
817         case STOCK_DEVICE_DEFAULT_FONT:
818         case STOCK_SYSTEM_FIXED_FONT:
819         case STOCK_DEFAULT_GUI_FONT:
820             magic = FONT_MAGIC;
821             break;
822
823         case STOCK_DEFAULT_PALETTE:
824             magic = PALETTE_MAGIC;
825             break;
826         }
827     }
828     else
829     {
830         GDIOBJHDR *object = (GDIOBJHDR *) GDI_HEAP_LOCK( handle );
831         if (object)
832         {
833             magic = object->wMagic;
834             GDI_HEAP_UNLOCK( handle );
835         }
836     }
837
838     if (magic >= PEN_MAGIC && magic <= METAFILE_DC_MAGIC)
839         return magic - PEN_MAGIC + 1;
840     else
841         return FALSE;
842 }
843
844
845 /***********************************************************************
846  *           SetObjectOwner16    (GDI.461)
847  */
848 void WINAPI SetObjectOwner16( HGDIOBJ16 handle, HANDLE16 owner )
849 {
850     /* Nothing to do */
851 }
852
853
854 /***********************************************************************
855  *           SetObjectOwner32    (GDI32.386)
856  */
857 void WINAPI SetObjectOwner32( HGDIOBJ32 handle, HANDLE32 owner )
858 {
859     /* Nothing to do */
860 }
861
862 /***********************************************************************
863  *           MakeObjectPrivate    (GDI.463)
864  */
865 void WINAPI MakeObjectPrivate( HGDIOBJ16 handle, BOOL16 private )
866 {
867     /* FIXME */
868 }
869
870
871 /***********************************************************************
872  *           GdiFlush    (GDI32.128)
873  */
874 BOOL32 WINAPI GdiFlush(void)
875 {
876     return TRUE;  /* FIXME */
877 }
878
879
880 /***********************************************************************
881  *           GdiGetBatchLimit    (GDI32.129)
882  */
883 DWORD WINAPI GdiGetBatchLimit(void)
884 {
885     return 1;  /* FIXME */
886 }
887
888
889 /***********************************************************************
890  *           GdiSetBatchLimit    (GDI32.139)
891  */
892 DWORD WINAPI GdiSetBatchLimit( DWORD limit )
893 {
894     return 1; /* FIXME */
895 }
896
897
898 /***********************************************************************
899  *           GdiSeeGdiDo   (GDI.452)
900  */
901 DWORD WINAPI GdiSeeGdiDo( WORD wReqType, WORD wParam1, WORD wParam2,
902                           WORD wParam3 )
903 {
904     switch (wReqType)
905     {
906     case 0x0001:  /* LocalAlloc */
907         return LOCAL_Alloc( GDI_HeapSel, wParam1, wParam3 );
908     case 0x0002:  /* LocalFree */
909         return LOCAL_Free( GDI_HeapSel, wParam1 );
910     case 0x0003:  /* LocalCompact */
911         return LOCAL_Compact( GDI_HeapSel, wParam3, 0 );
912     case 0x0103:  /* LocalHeap */
913         return GDI_HeapSel;
914     default:
915         WARN(gdi, "(wReqType=%04x): Unknown\n", wReqType);
916         return (DWORD)-1;
917     }
918 }
919
920 /***********************************************************************
921  *           MulDiv16   (GDI.128)
922  */
923 INT16 WINAPI MulDiv16( INT16 foo, INT16 bar, INT16 baz )
924 {
925     INT32 ret;
926     if (!baz) return -32768;
927     ret = (foo * bar) / baz;
928     if ((ret > 32767) || (ret < -32767)) return -32768;
929     return ret;
930 }
931
932
933 /***********************************************************************
934  *           MulDiv32   (KERNEL32.391)
935  * RETURNS
936  *      Result of multiplication and division
937  *      -1: Overflow occurred or Divisor was 0
938  */
939 INT32 WINAPI MulDiv32(
940              INT32 nMultiplicand, 
941              INT32 nMultiplier,
942              INT32 nDivisor
943 ) {
944 #if (SIZEOF_LONG_LONG >= 8)
945     long long ret;
946     if (!nDivisor) return -1;
947     ret = ((long long)nMultiplicand * nMultiplier) / nDivisor;
948     if ((ret > 2147483647) || (ret < -2147483647)) return -1;
949     return ret;
950 #else
951     if (!nDivisor) return -1;
952     return (nMultiplicand * nMultiplier) / nDivisor;
953 #endif
954 }