Release 20010305.
[wine] / graphics / x11drv / brush.c
1 /*
2  * X11DRV brush objects
3  *
4  * Copyright 1993, 1994  Alexandre Julliard
5  */
6
7 #include "config.h"
8
9 #include "ts_xlib.h"
10
11 #include <stdlib.h>
12 #include "brush.h"
13 #include "bitmap.h"
14 #include "color.h"
15 #include "x11drv.h"
16 #include "debugtools.h"
17
18 DEFAULT_DEBUG_CHANNEL(gdi);
19
20 static const char HatchBrushes[NB_HATCH_STYLES + 1][8] =
21 {
22     { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 }, /* HS_HORIZONTAL */
23     { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, /* HS_VERTICAL   */
24     { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, /* HS_FDIAGONAL  */
25     { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }, /* HS_BDIAGONAL  */
26     { 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08 }, /* HS_CROSS      */
27     { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 }, /* HS_DIAGCROSS  */
28     { 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb }  /* Hack for DKGRAY */
29 };
30
31   /* Levels of each primary for dithering */
32 #define PRIMARY_LEVELS  3  
33 #define TOTAL_LEVELS    (PRIMARY_LEVELS*PRIMARY_LEVELS*PRIMARY_LEVELS)
34
35  /* Dithering matrix size  */
36 #define MATRIX_SIZE     8
37 #define MATRIX_SIZE_2   (MATRIX_SIZE*MATRIX_SIZE)
38
39   /* Total number of possible levels for a dithered primary color */
40 #define DITHER_LEVELS   (MATRIX_SIZE_2 * (PRIMARY_LEVELS-1) + 1)
41
42   /* Dithering matrix */
43 static const int dither_matrix[MATRIX_SIZE_2] =
44 {
45      0, 32,  8, 40,  2, 34, 10, 42,
46     48, 16, 56, 24, 50, 18, 58, 26,
47     12, 44,  4, 36, 14, 46,  6, 38,
48     60, 28, 52, 20, 62, 30, 54, 22,
49      3, 35, 11, 43,  1, 33,  9, 41,
50     51, 19, 59, 27, 49, 17, 57, 25,
51     15, 47,  7, 39, 13, 45,  5, 37,
52     63, 31, 55, 23, 61, 29, 53, 21
53 };
54
55   /* Mapping between (R,G,B) triples and EGA colors */
56 static const int EGAmapping[TOTAL_LEVELS] =
57 {
58     0,  /* 000000 -> 000000 */
59     4,  /* 00007f -> 000080 */
60     12, /* 0000ff -> 0000ff */
61     2,  /* 007f00 -> 008000 */
62     6,  /* 007f7f -> 008080 */
63     6,  /* 007fff -> 008080 */
64     10, /* 00ff00 -> 00ff00 */
65     6,  /* 00ff7f -> 008080 */
66     14, /* 00ffff -> 00ffff */
67     1,  /* 7f0000 -> 800000 */
68     5,  /* 7f007f -> 800080 */
69     5,  /* 7f00ff -> 800080 */
70     3,  /* 7f7f00 -> 808000 */
71     8,  /* 7f7f7f -> 808080 */
72     7,  /* 7f7fff -> c0c0c0 */
73     3,  /* 7fff00 -> 808000 */
74     7,  /* 7fff7f -> c0c0c0 */
75     7,  /* 7fffff -> c0c0c0 */
76     9,  /* ff0000 -> ff0000 */
77     5,  /* ff007f -> 800080 */
78     13, /* ff00ff -> ff00ff */
79     3,  /* ff7f00 -> 808000 */
80     7,  /* ff7f7f -> c0c0c0 */
81     7,  /* ff7fff -> c0c0c0 */
82     11, /* ffff00 -> ffff00 */
83     7,  /* ffff7f -> c0c0c0 */
84     15  /* ffffff -> ffffff */
85 };
86
87 #define PIXEL_VALUE(r,g,b) \
88     X11DRV_PALETTE_mapEGAPixel[EGAmapping[((r)*PRIMARY_LEVELS+(g))*PRIMARY_LEVELS+(b)]]
89
90   /* X image for building dithered pixmap */
91 static XImage *ditherImage = NULL;
92
93
94 /***********************************************************************
95  *           BRUSH_Init
96  *
97  * Create the X image used for dithering.
98  */
99 BOOL X11DRV_BRUSH_Init(void)
100 {
101     XCREATEIMAGE( ditherImage, MATRIX_SIZE, MATRIX_SIZE, X11DRV_GetDepth() );
102     return (ditherImage != NULL);
103 }
104
105
106 /***********************************************************************
107  *           BRUSH_DitherColor
108  */
109 static Pixmap BRUSH_DitherColor( DC *dc, COLORREF color )
110 {
111     static COLORREF prevColor = 0xffffffff;
112     unsigned int x, y;
113     Pixmap pixmap;
114
115     wine_tsx11_lock();
116     if (color != prevColor)
117     {
118         int r = GetRValue( color ) * DITHER_LEVELS;
119         int g = GetGValue( color ) * DITHER_LEVELS;
120         int b = GetBValue( color ) * DITHER_LEVELS;
121         const int *pmatrix = dither_matrix;
122
123         for (y = 0; y < MATRIX_SIZE; y++)
124         {
125             for (x = 0; x < MATRIX_SIZE; x++)
126             {
127                 int d  = *pmatrix++ * 256;
128                 int dr = ((r + d) / MATRIX_SIZE_2) / 256;
129                 int dg = ((g + d) / MATRIX_SIZE_2) / 256;
130                 int db = ((b + d) / MATRIX_SIZE_2) / 256;
131                 XPutPixel( ditherImage, x, y, PIXEL_VALUE(dr,dg,db) );
132             }
133         }
134         prevColor = color;
135     }
136     
137     pixmap = XCreatePixmap( display, X11DRV_GetXRootWindow(),
138                             MATRIX_SIZE, MATRIX_SIZE, X11DRV_GetDepth() );
139     XPutImage( display, pixmap, BITMAP_colorGC, ditherImage, 0, 0,
140                0, 0, MATRIX_SIZE, MATRIX_SIZE );
141     wine_tsx11_unlock();
142     return pixmap;
143 }
144
145
146 /***********************************************************************
147  *           BRUSH_SelectSolidBrush
148  */
149 static void BRUSH_SelectSolidBrush( DC *dc, COLORREF color )
150 {
151     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
152
153     if ((dc->bitsPerPixel > 1) && (X11DRV_GetDepth() <= 8) && !COLOR_IsSolid( color ))
154     {
155           /* Dithered brush */
156         physDev->brush.pixmap = BRUSH_DitherColor( dc, color );
157         physDev->brush.fillStyle = FillTiled;
158         physDev->brush.pixel = 0;
159     }
160     else
161     {
162           /* Solid brush */
163         physDev->brush.pixel = X11DRV_PALETTE_ToPhysical( dc, color );
164         physDev->brush.fillStyle = FillSolid;
165     }
166 }
167
168
169 /***********************************************************************
170  *           BRUSH_SelectPatternBrush
171  */
172 static BOOL BRUSH_SelectPatternBrush( DC * dc, HBITMAP hbitmap )
173 {
174     BOOL ret = FALSE;
175     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
176     BITMAPOBJ * bmp = (BITMAPOBJ *) GDI_GetObjPtr( hbitmap, BITMAP_MAGIC );
177     if (!bmp) return FALSE;
178
179    if(!bmp->physBitmap)
180         if(!X11DRV_CreateBitmap(hbitmap))
181             goto done;
182
183     if(bmp->funcs != dc->funcs) {
184         WARN("Trying to select non-X11 DDB into an X11 dc\n");
185         goto done;
186     }
187
188     if ((dc->bitsPerPixel == 1) && (bmp->bitmap.bmBitsPixel != 1))
189     {
190         /* Special case: a color pattern on a monochrome DC */
191         physDev->brush.pixmap = TSXCreatePixmap( display, X11DRV_GetXRootWindow(), 8, 8, 1);
192         /* FIXME: should probably convert to monochrome instead */
193         TSXCopyPlane( display, (Pixmap)bmp->physBitmap, physDev->brush.pixmap,
194                     BITMAP_monoGC, 0, 0, 8, 8, 0, 0, 1 );
195     }
196     else
197     {
198         physDev->brush.pixmap = TSXCreatePixmap( display, X11DRV_GetXRootWindow(),
199                                                8, 8, bmp->bitmap.bmBitsPixel );
200         TSXCopyArea( display, (Pixmap)bmp->physBitmap, physDev->brush.pixmap,
201                    BITMAP_GC(bmp), 0, 0, 8, 8, 0, 0 );
202     }
203     
204     if (bmp->bitmap.bmBitsPixel > 1)
205     {
206         physDev->brush.fillStyle = FillTiled;
207         physDev->brush.pixel = 0;  /* Ignored */
208     }
209     else
210     {
211         physDev->brush.fillStyle = FillOpaqueStippled;
212         physDev->brush.pixel = -1;  /* Special case (see DC_SetupGCForBrush) */
213     }
214     ret = TRUE;
215  done:
216     GDI_ReleaseObj( hbitmap );
217     return ret;
218 }
219
220
221
222
223 /***********************************************************************
224  *           BRUSH_SelectObject
225  */
226 HBRUSH X11DRV_BRUSH_SelectObject( DC * dc, HBRUSH hbrush, BRUSHOBJ * brush )
227 {
228     HBITMAP16 hBitmap;
229     BITMAPINFO * bmpInfo;
230     HBRUSH16 prevHandle = dc->hBrush;
231     X11DRV_PDEVICE *physDev = (X11DRV_PDEVICE *)dc->physDev;
232     
233     TRACE("hdc=%04x hbrush=%04x\n",
234                 dc->hSelf,hbrush);
235
236     dc->hBrush = hbrush;
237
238     if (physDev->brush.pixmap)
239     {
240         TSXFreePixmap( display, physDev->brush.pixmap );
241         physDev->brush.pixmap = 0;
242     }
243     physDev->brush.style = brush->logbrush.lbStyle;
244     
245     switch(brush->logbrush.lbStyle)
246     {
247       case BS_NULL:
248         TRACE("BS_NULL\n" );
249         break;
250
251       case BS_SOLID:
252         TRACE("BS_SOLID\n" );
253         BRUSH_SelectSolidBrush( dc, brush->logbrush.lbColor );
254         break;
255         
256       case BS_HATCHED:
257         TRACE("BS_HATCHED\n" );
258         physDev->brush.pixel = X11DRV_PALETTE_ToPhysical( dc, brush->logbrush.lbColor );
259         physDev->brush.pixmap = TSXCreateBitmapFromData( display, X11DRV_GetXRootWindow(),
260                                  HatchBrushes[brush->logbrush.lbHatch], 8, 8 );
261         physDev->brush.fillStyle = FillStippled;
262         break;
263         
264       case BS_PATTERN:
265         TRACE("BS_PATTERN\n");
266         BRUSH_SelectPatternBrush( dc, (HBRUSH16)brush->logbrush.lbHatch );
267         break;
268
269       case BS_DIBPATTERN:
270         TRACE("BS_DIBPATTERN\n");
271         if ((bmpInfo = (BITMAPINFO *) GlobalLock16( (HGLOBAL16)brush->logbrush.lbHatch )))
272         {
273             int size = DIB_BitmapInfoSize( bmpInfo, brush->logbrush.lbColor );
274             hBitmap = CreateDIBitmap( dc->hSelf, &bmpInfo->bmiHeader,
275                                         CBM_INIT, ((char *)bmpInfo) + size,
276                                         bmpInfo,
277                                         (WORD)brush->logbrush.lbColor );
278             BRUSH_SelectPatternBrush( dc, hBitmap );
279             DeleteObject16( hBitmap );
280             GlobalUnlock16( (HGLOBAL16)brush->logbrush.lbHatch );           
281         }
282         
283         break;
284     }
285     
286     return prevHandle;
287 }