xref: /reactos/win32ss/gdi/eng/engbrush.c (revision c2c66aff)
1 /*
2  * COPYRIGHT:         See COPYING in the top level directory
3  * PROJECT:           ReactOS kernel
4  * PURPOSE:           GDI Driver Brush Functions
5  * FILE:              win32ss/gdi/eng/engbrush.c
6  * PROGRAMER:         Jason Filby
7  *                    Timo Kreuzer
8  */
9 
10 #include <win32k.h>
11 
12 DBG_DEFAULT_CHANNEL(EngBrush);
13 
14 static const ULONG gaulHatchBrushes[HS_DDI_MAX][8] =
15 {
16     {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF}, /* HS_HORIZONTAL */
17     {0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7}, /* HS_VERTICAL   */
18     {0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F}, /* HS_FDIAGONAL  */
19     {0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE}, /* HS_BDIAGONAL  */
20     {0xF7, 0xF7, 0xF7, 0xF7, 0x00, 0xF7, 0xF7, 0xF7}, /* HS_CROSS      */
21     {0x7E, 0xBD, 0xDB, 0xE7, 0xE7, 0xDB, 0xBD, 0x7E}  /* HS_DIAGCROSS  */
22 };
23 
24 HSURF gahsurfHatch[HS_DDI_MAX];
25 
26 /** Internal functions ********************************************************/
27 
28 INIT_FUNCTION
29 NTSTATUS
30 NTAPI
31 InitBrushImpl(VOID)
32 {
33     ULONG i;
34     SIZEL sizl = {8, 8};
35 
36     /* Loop all hatch styles */
37     for (i = 0; i < HS_DDI_MAX; i++)
38     {
39         /* Create a default hatch bitmap */
40         gahsurfHatch[i] = (HSURF)EngCreateBitmap(sizl,
41                                                  0,
42                                                  BMF_1BPP,
43                                                  0,
44                                                  (PVOID)gaulHatchBrushes[i]);
45     }
46 
47     return STATUS_SUCCESS;
48 }
49 
50 VOID
51 NTAPI
52 EBRUSHOBJ_vInit(EBRUSHOBJ *pebo,
53     PBRUSH pbrush,
54     PSURFACE psurf,
55     COLORREF crBackgroundClr,
56     COLORREF crForegroundClr,
57     PPALETTE ppalDC)
58 {
59     ASSERT(pebo);
60     ASSERT(pbrush);
61 
62     pebo->BrushObject.flColorType = 0;
63     pebo->BrushObject.pvRbrush = NULL;
64     pebo->pbrush = pbrush;
65     pebo->pengbrush = NULL;
66     pebo->flattrs = pbrush->flAttrs;
67     pebo->psoMask = NULL;
68 
69     /* Initialize 1 bpp fore and back colors */
70     pebo->crCurrentBack = crBackgroundClr;
71     pebo->crCurrentText = crForegroundClr;
72 
73     pebo->psurfTrg = psurf;
74     /* We are initializing for a new memory DC */
75     if(!pebo->psurfTrg)
76         pebo->psurfTrg = psurfDefaultBitmap;
77     ASSERT(pebo->psurfTrg);
78     ASSERT(pebo->psurfTrg->ppal);
79 
80     /* Initialize palettes */
81     pebo->ppalSurf = pebo->psurfTrg->ppal;
82     GDIOBJ_vReferenceObjectByPointer(&pebo->ppalSurf->BaseObject);
83     pebo->ppalDC = ppalDC;
84     if(!pebo->ppalDC)
85         pebo->ppalDC = gppalDefault;
86     GDIOBJ_vReferenceObjectByPointer(&pebo->ppalDC->BaseObject);
87     pebo->ppalDIB = NULL;
88 
89     if (pbrush->flAttrs & BR_IS_NULL)
90     {
91         /* NULL brushes don't need a color */
92         pebo->BrushObject.iSolidColor = 0;
93     }
94     else if (pbrush->flAttrs & BR_IS_SOLID)
95     {
96         /* Set the RGB color */
97         EBRUSHOBJ_vSetSolidRGBColor(pebo, pbrush->BrushAttr.lbColor);
98     }
99     else
100     {
101         /* This is a pattern brush that needs realization */
102         pebo->BrushObject.iSolidColor = 0xFFFFFFFF;
103 
104         /* Use foreground color of hatch brushes */
105         if (pbrush->flAttrs & BR_IS_HATCH)
106             pebo->crCurrentText = pbrush->BrushAttr.lbColor;
107     }
108 }
109 
110 VOID
111 NTAPI
112 EBRUSHOBJ_vInitFromDC(EBRUSHOBJ *pebo,
113     PBRUSH pbrush, PDC pdc)
114 {
115     EBRUSHOBJ_vInit(pebo, pbrush, pdc->dclevel.pSurface,
116         pdc->pdcattr->crBackgroundClr, pdc->pdcattr->crForegroundClr,
117         pdc->dclevel.ppal);
118 }
119 
120 VOID
121 FASTCALL
122 EBRUSHOBJ_vSetSolidRGBColor(EBRUSHOBJ *pebo, COLORREF crColor)
123 {
124     ULONG iSolidColor;
125     EXLATEOBJ exlo;
126 
127     /* Never use with non-solid brushes */
128     ASSERT(pebo->flattrs & BR_IS_SOLID);
129 
130     /* Set the RGB color */
131     crColor &= 0xFFFFFF;
132     pebo->crRealize = crColor;
133     pebo->ulRGBColor = crColor;
134 
135     /* Initialize an XLATEOBJ RGB -> surface */
136     EXLATEOBJ_vInitialize(&exlo,
137                           &gpalRGB,
138                           pebo->ppalSurf,
139                           pebo->crCurrentBack,
140                           0,
141                           0);
142 
143     /* Translate the brush color to the target format */
144     iSolidColor = XLATEOBJ_iXlate(&exlo.xlo, crColor);
145     pebo->BrushObject.iSolidColor = iSolidColor;
146 
147     /* Clean up the XLATEOBJ */
148     EXLATEOBJ_vCleanup(&exlo);
149 }
150 
151 VOID
152 NTAPI
153 EBRUSHOBJ_vCleanup(EBRUSHOBJ *pebo)
154 {
155     /* Check if there's a GDI realisation */
156     if (pebo->pengbrush)
157     {
158         /* Unlock the bitmap again */
159         SURFACE_ShareUnlockSurface(pebo->pengbrush);
160         pebo->pengbrush = NULL;
161     }
162 
163     /* Check if there's a driver's realisation */
164     if (pebo->BrushObject.pvRbrush)
165     {
166         /* Free allocated driver memory */
167         EngFreeMem(pebo->BrushObject.pvRbrush);
168         pebo->BrushObject.pvRbrush = NULL;
169     }
170 
171     if (pebo->psoMask != NULL)
172     {
173         SURFACE_ShareUnlockSurface(pebo->psoMask);
174         pebo->psoMask = NULL;
175     }
176 
177     /* Dereference the palettes */
178     if (pebo->ppalSurf)
179     {
180         PALETTE_ShareUnlockPalette(pebo->ppalSurf);
181     }
182     if (pebo->ppalDC)
183     {
184         PALETTE_ShareUnlockPalette(pebo->ppalDC);
185     }
186     if (pebo->ppalDIB)
187     {
188         PALETTE_ShareUnlockPalette(pebo->ppalDIB);
189     }
190 }
191 
192 VOID
193 NTAPI
194 EBRUSHOBJ_vUpdateFromDC(
195     EBRUSHOBJ *pebo,
196     PBRUSH pbrush,
197     PDC pdc)
198 {
199     /* Cleanup the brush */
200     EBRUSHOBJ_vCleanup(pebo);
201 
202     /* Reinitialize */
203     EBRUSHOBJ_vInitFromDC(pebo, pbrush, pdc);
204 }
205 
206 /**
207  * This function is not exported, because it makes no sense for
208  * The driver to punt back to this function */
209 BOOL
210 APIENTRY
211 EngRealizeBrush(
212     BRUSHOBJ *pbo,
213     SURFOBJ  *psoDst,
214     SURFOBJ  *psoPattern,
215     SURFOBJ  *psoMask,
216     XLATEOBJ *pxlo,
217     ULONG    iHatch)
218 {
219     EBRUSHOBJ *pebo;
220     HBITMAP hbmpRealize;
221     SURFOBJ *psoRealize;
222     PSURFACE psurfRealize;
223     POINTL ptlSrc = {0, 0};
224     RECTL rclDest;
225     ULONG lWidth;
226 
227     /* Calculate width in bytes of the realized brush */
228     lWidth = WIDTH_BYTES_ALIGN32(psoPattern->sizlBitmap.cx,
229                                   BitsPerFormat(psoDst->iBitmapFormat));
230 
231     /* Allocate a bitmap */
232     hbmpRealize = EngCreateBitmap(psoPattern->sizlBitmap,
233                                   lWidth,
234                                   psoDst->iBitmapFormat,
235                                   BMF_NOZEROINIT,
236                                   NULL);
237     if (!hbmpRealize)
238     {
239         return FALSE;
240     }
241 
242     /* Lock the bitmap */
243     psurfRealize = SURFACE_ShareLockSurface(hbmpRealize);
244 
245     /* Already delete the pattern bitmap (will be kept until dereferenced) */
246     EngDeleteSurface((HSURF)hbmpRealize);
247 
248     if (!psurfRealize)
249     {
250         return FALSE;
251     }
252 
253     /* Copy the bits to the new format bitmap */
254     rclDest.left = rclDest.top = 0;
255     rclDest.right = psoPattern->sizlBitmap.cx;
256     rclDest.bottom = psoPattern->sizlBitmap.cy;
257     psoRealize = &psurfRealize->SurfObj;
258     EngCopyBits(psoRealize, psoPattern, NULL, pxlo, &rclDest, &ptlSrc);
259 
260 
261     pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
262     pebo->pengbrush = (PVOID)psurfRealize;
263 
264     return TRUE;
265 }
266 
267 static
268 PPALETTE
269 FixupDIBBrushPalette(
270     _In_ PPALETTE ppalDIB,
271     _In_ PPALETTE ppalDC)
272 {
273     PPALETTE ppalNew;
274     ULONG i, iPalIndex, crColor;
275 
276     /* Allocate a new palette */
277     ppalNew = PALETTE_AllocPalette(PAL_INDEXED,
278                                    ppalDIB->NumColors,
279                                    NULL,
280                                    0,
281                                    0,
282                                    0);
283     if (ppalNew == NULL)
284     {
285         ERR("Failed to allcate palette for brush\n");
286         return NULL;
287     }
288 
289     /* Loop all colors */
290     for (i = 0; i < ppalDIB->NumColors; i++)
291     {
292         /* Get the RGB color, which is the index into the DC palette */
293         iPalIndex = PALETTE_ulGetRGBColorFromIndex(ppalDIB, i);
294 
295         /* Roll over when index is too big */
296         iPalIndex %= ppalDC->NumColors;
297 
298         /* Set the indexed DC color as the new color */
299         crColor = PALETTE_ulGetRGBColorFromIndex(ppalDC, iPalIndex);
300         PALETTE_vSetRGBColorForIndex(ppalNew, i, crColor);
301     }
302 
303     /* Return the new palette */
304     return ppalNew;
305 }
306 
307 BOOL
308 NTAPI
309 EBRUSHOBJ_bRealizeBrush(EBRUSHOBJ *pebo, BOOL bCallDriver)
310 {
311     BOOL bResult;
312     PFN_DrvRealizeBrush pfnRealizeBrush = NULL;
313     PSURFACE psurfPattern;
314     SURFOBJ *psoMask;
315     PPDEVOBJ ppdev;
316     EXLATEOBJ exlo;
317     PPALETTE ppalPattern;
318     PBRUSH pbr = pebo->pbrush;
319     HBITMAP hbmPattern;
320     ULONG iHatch;
321 
322     /* All EBRUSHOBJs have a surface, see EBRUSHOBJ_vInit */
323     ASSERT(pebo->psurfTrg);
324 
325     ppdev = (PPDEVOBJ)pebo->psurfTrg->SurfObj.hdev;
326     if (!ppdev)
327         ppdev = gppdevPrimary;
328 
329     if (bCallDriver)
330     {
331         /* Get the Drv function */
332         pfnRealizeBrush = ppdev->DriverFunctions.RealizeBrush;
333         if (pfnRealizeBrush == NULL)
334         {
335             ERR("No DrvRealizeBrush. Cannot realize brush\n");
336             return FALSE;
337         }
338 
339         /* Get the mask */
340         psoMask = EBRUSHOBJ_psoMask(pebo);
341     }
342     else
343     {
344         /* Use the Eng function */
345         pfnRealizeBrush = EngRealizeBrush;
346 
347         /* We don't handle the mask bitmap here. We do this only on demand */
348         psoMask = NULL;
349     }
350 
351     /* Check if this is a hatch brush */
352     if (pbr->flAttrs & BR_IS_HATCH)
353     {
354         /* Get the hatch brush pattern from the PDEV */
355         hbmPattern = (HBITMAP)ppdev->ahsurf[pbr->iHatch];
356         iHatch = pbr->iHatch;
357     }
358     else
359     {
360         /* Use the brushes pattern */
361         hbmPattern = pbr->hbmPattern;
362         iHatch = -1;
363     }
364 
365     psurfPattern = SURFACE_ShareLockSurface(hbmPattern);
366     ASSERT(psurfPattern);
367     ASSERT(psurfPattern->ppal);
368 
369     /* DIB brushes with DIB_PAL_COLORS usage need a new palette */
370     if (pbr->flAttrs & BR_IS_DIBPALCOLORS)
371     {
372         /* Create a palette with the colors from the DC */
373         ppalPattern = FixupDIBBrushPalette(psurfPattern->ppal, pebo->ppalDC);
374         if (ppalPattern == NULL)
375         {
376             ERR("FixupDIBBrushPalette() failed.\n");
377             return FALSE;
378         }
379 
380         pebo->ppalDIB = ppalPattern;
381     }
382     else
383     {
384         /* The palette is already as it should be */
385         ppalPattern = psurfPattern->ppal;
386     }
387 
388     /* Initialize XLATEOBJ for the brush */
389     EXLATEOBJ_vInitialize(&exlo,
390                           ppalPattern,
391                           pebo->psurfTrg->ppal,
392                           0,
393                           pebo->crCurrentBack,
394                           pebo->crCurrentText);
395 
396     /* Create the realization */
397     bResult = pfnRealizeBrush(&pebo->BrushObject,
398                               &pebo->psurfTrg->SurfObj,
399                               &psurfPattern->SurfObj,
400                               psoMask,
401                               &exlo.xlo,
402                               iHatch);
403 
404     /* Cleanup the XLATEOBJ */
405     EXLATEOBJ_vCleanup(&exlo);
406 
407     /* Unlock surface */
408     SURFACE_ShareUnlockSurface(psurfPattern);
409 
410     return bResult;
411 }
412 
413 PVOID
414 NTAPI
415 EBRUSHOBJ_pvGetEngBrush(EBRUSHOBJ *pebo)
416 {
417     BOOL bResult;
418 
419     if (!pebo->pengbrush)
420     {
421         bResult = EBRUSHOBJ_bRealizeBrush(pebo, FALSE);
422         if (!bResult)
423         {
424             if (pebo->pengbrush)
425                 EngDeleteSurface(pebo->pengbrush);
426             pebo->pengbrush = NULL;
427         }
428     }
429 
430     return pebo->pengbrush;
431 }
432 
433 SURFOBJ*
434 NTAPI
435 EBRUSHOBJ_psoPattern(EBRUSHOBJ *pebo)
436 {
437     PSURFACE psurfPattern;
438 
439     psurfPattern = EBRUSHOBJ_pvGetEngBrush(pebo);
440 
441     return psurfPattern ? &psurfPattern->SurfObj : NULL;
442 }
443 
444 SURFOBJ*
445 NTAPI
446 EBRUSHOBJ_psoMask(EBRUSHOBJ *pebo)
447 {
448     HBITMAP hbmMask;
449     PSURFACE psurfMask;
450     PPDEVOBJ ppdev;
451 
452     /* Check if we don't have a mask yet */
453     if (pebo->psoMask == NULL)
454     {
455         /* Check if this is a hatch brush */
456         if (pebo->flattrs & BR_IS_HATCH)
457         {
458             /* Get the PDEV */
459             ppdev = (PPDEVOBJ)pebo->psurfTrg->SurfObj.hdev;
460             if (!ppdev)
461                 ppdev = gppdevPrimary;
462 
463             /* Use the hatch bitmap as the mask */
464             hbmMask = (HBITMAP)ppdev->ahsurf[pebo->pbrush->iHatch];
465             psurfMask = SURFACE_ShareLockSurface(hbmMask);
466             if (psurfMask == NULL)
467             {
468                 ERR("Failed to lock hatch brush for PDEV %p, iHatch %lu\n",
469                     ppdev, pebo->pbrush->iHatch);
470                 return NULL;
471             }
472 
473             NT_ASSERT(psurfMask->SurfObj.iBitmapFormat == BMF_1BPP);
474             pebo->psoMask = &psurfMask->SurfObj;
475         }
476     }
477 
478     return pebo->psoMask;
479 }
480 
481 /** Exported DDI functions ****************************************************/
482 
483 /*
484  * @implemented
485  */
486 PVOID APIENTRY
487 BRUSHOBJ_pvAllocRbrush(
488     IN BRUSHOBJ *pbo,
489     IN ULONG cj)
490 {
491     pbo->pvRbrush = EngAllocMem(0, cj, GDITAG_RBRUSH);
492     return pbo->pvRbrush;
493 }
494 
495 /*
496  * @implemented
497  */
498 PVOID APIENTRY
499 BRUSHOBJ_pvGetRbrush(
500     IN BRUSHOBJ *pbo)
501 {
502     EBRUSHOBJ *pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
503     BOOL bResult;
504 
505     if (!pbo->pvRbrush)
506     {
507         bResult = EBRUSHOBJ_bRealizeBrush(pebo, TRUE);
508         if (!bResult)
509         {
510             if (pbo->pvRbrush)
511             {
512                 EngFreeMem(pbo->pvRbrush);
513                 pbo->pvRbrush = NULL;
514             }
515         }
516     }
517 
518     return pbo->pvRbrush;
519 }
520 
521 /*
522  * @implemented
523  */
524 ULONG APIENTRY
525 BRUSHOBJ_ulGetBrushColor(
526     IN BRUSHOBJ *pbo)
527 {
528     EBRUSHOBJ *pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
529     return pebo->ulRGBColor;
530 }
531 
532 /* EOF */
533