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 CODE_SEG("INIT")
29 NTSTATUS
30 NTAPI
InitBrushImpl(VOID)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
EBRUSHOBJ_vInit(EBRUSHOBJ * pebo,PBRUSH pbrush,PSURFACE psurf,COLORREF crBackgroundClr,COLORREF crForegroundClr,PPALETTE ppalDC)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
EBRUSHOBJ_vInitFromDC(EBRUSHOBJ * pebo,PBRUSH pbrush,PDC pdc)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
EBRUSHOBJ_vSetSolidRGBColor(EBRUSHOBJ * pebo,COLORREF crColor)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
EBRUSHOBJ_vCleanup(EBRUSHOBJ * pebo)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
EBRUSHOBJ_vUpdateFromDC(EBRUSHOBJ * pebo,PBRUSH pbrush,PDC pdc)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
EngRealizeBrush(BRUSHOBJ * pbo,SURFOBJ * psoDst,SURFOBJ * psoPattern,SURFOBJ * psoMask,XLATEOBJ * pxlo,ULONG iHatch)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
FixupDIBBrushPalette(_In_ PPALETTE ppalDIB,_In_ PPALETTE ppalDC)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
EBRUSHOBJ_bRealizeBrush(EBRUSHOBJ * pebo,BOOL bCallDriver)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 = gpmdev->ppdevGlobal;
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
EBRUSHOBJ_pvGetEngBrush(EBRUSHOBJ * pebo)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
EBRUSHOBJ_psoPattern(EBRUSHOBJ * pebo)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
EBRUSHOBJ_psoMask(EBRUSHOBJ * pebo)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 = gpmdev->ppdevGlobal;
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
BRUSHOBJ_pvAllocRbrush(IN BRUSHOBJ * pbo,IN ULONG cj)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
BRUSHOBJ_pvGetRbrush(IN BRUSHOBJ * pbo)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
BRUSHOBJ_ulGetBrushColor(IN BRUSHOBJ * pbo)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