a078c057b21aee8c17112c2b8753f5e4b942ca8a
[reactos.git] / reactos / win32ss / gdi / eng / engbrush.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: GDI Driver Brush Functions
5 * FILE: subsystem/win32/win32k/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 PALETTE_ShareUnlockPalette(pebo->ppalSurf);
179 PALETTE_ShareUnlockPalette(pebo->ppalDC);
180 if (pebo->ppalDIB) PALETTE_ShareUnlockPalette(pebo->ppalDIB);
181 }
182
183 VOID
184 NTAPI
185 EBRUSHOBJ_vUpdateFromDC(
186 EBRUSHOBJ *pebo,
187 PBRUSH pbrush,
188 PDC pdc)
189 {
190 /* Cleanup the brush */
191 EBRUSHOBJ_vCleanup(pebo);
192
193 /* Reinitialize */
194 EBRUSHOBJ_vInitFromDC(pebo, pbrush, pdc);
195 }
196
197 /**
198 * This function is not exported, because it makes no sense for
199 * The driver to punt back to this function */
200 BOOL
201 APIENTRY
202 EngRealizeBrush(
203 BRUSHOBJ *pbo,
204 SURFOBJ *psoDst,
205 SURFOBJ *psoPattern,
206 SURFOBJ *psoMask,
207 XLATEOBJ *pxlo,
208 ULONG iHatch)
209 {
210 EBRUSHOBJ *pebo;
211 HBITMAP hbmpRealize;
212 SURFOBJ *psoRealize;
213 PSURFACE psurfRealize;
214 POINTL ptlSrc = {0, 0};
215 RECTL rclDest;
216 ULONG lWidth;
217
218 /* Calculate width in bytes of the realized brush */
219 lWidth = WIDTH_BYTES_ALIGN32(psoPattern->sizlBitmap.cx,
220 BitsPerFormat(psoDst->iBitmapFormat));
221
222 /* Allocate a bitmap */
223 hbmpRealize = EngCreateBitmap(psoPattern->sizlBitmap,
224 lWidth,
225 psoDst->iBitmapFormat,
226 BMF_NOZEROINIT,
227 NULL);
228 if (!hbmpRealize)
229 {
230 return FALSE;
231 }
232
233 /* Lock the bitmap */
234 psurfRealize = SURFACE_ShareLockSurface(hbmpRealize);
235
236 /* Already delete the pattern bitmap (will be kept until dereferenced) */
237 EngDeleteSurface((HSURF)hbmpRealize);
238
239 if (!psurfRealize)
240 {
241 return FALSE;
242 }
243
244 /* Copy the bits to the new format bitmap */
245 rclDest.left = rclDest.top = 0;
246 rclDest.right = psoPattern->sizlBitmap.cx;
247 rclDest.bottom = psoPattern->sizlBitmap.cy;
248 psoRealize = &psurfRealize->SurfObj;
249 EngCopyBits(psoRealize, psoPattern, NULL, pxlo, &rclDest, &ptlSrc);
250
251
252 pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
253 pebo->pengbrush = (PVOID)psurfRealize;
254
255 return TRUE;
256 }
257
258 static
259 PPALETTE
260 FixupDIBBrushPalette(
261 _In_ PPALETTE ppalDIB,
262 _In_ PPALETTE ppalDC)
263 {
264 PPALETTE ppalNew;
265 ULONG i, iPalIndex, crColor;
266
267 /* Allocate a new palette */
268 ppalNew = PALETTE_AllocPalette(PAL_INDEXED,
269 ppalDIB->NumColors,
270 NULL,
271 0,
272 0,
273 0);
274 if (ppalNew == NULL)
275 {
276 ERR("Failed to allcate palette for brush\n");
277 return NULL;
278 }
279
280 /* Loop all colors */
281 for (i = 0; i < ppalDIB->NumColors; i++)
282 {
283 /* Get the RGB color, which is the index into the DC palette */
284 iPalIndex = PALETTE_ulGetRGBColorFromIndex(ppalDIB, i);
285
286 /* Roll over when index is too big */
287 iPalIndex %= ppalDC->NumColors;
288
289 /* Set the indexed DC color as the new color */
290 crColor = PALETTE_ulGetRGBColorFromIndex(ppalDC, iPalIndex);
291 PALETTE_vSetRGBColorForIndex(ppalNew, i, crColor);
292 }
293
294 /* Return the new palette */
295 return ppalNew;
296 }
297
298 BOOL
299 NTAPI
300 EBRUSHOBJ_bRealizeBrush(EBRUSHOBJ *pebo, BOOL bCallDriver)
301 {
302 BOOL bResult;
303 PFN_DrvRealizeBrush pfnRealizeBrush = NULL;
304 PSURFACE psurfPattern;
305 SURFOBJ *psoMask;
306 PPDEVOBJ ppdev;
307 EXLATEOBJ exlo;
308 PPALETTE ppalPattern;
309 PBRUSH pbr = pebo->pbrush;
310 HBITMAP hbmPattern;
311 ULONG iHatch;
312
313 /* All EBRUSHOBJs have a surface, see EBRUSHOBJ_vInit */
314 ASSERT(pebo->psurfTrg);
315
316 ppdev = (PPDEVOBJ)pebo->psurfTrg->SurfObj.hdev;
317 if (!ppdev)
318 ppdev = gppdevPrimary;
319
320 if (bCallDriver)
321 {
322 /* Get the Drv function */
323 pfnRealizeBrush = ppdev->DriverFunctions.RealizeBrush;
324 if (pfnRealizeBrush == NULL)
325 {
326 ERR("No DrvRealizeBrush. Cannot realize brush\n");
327 return FALSE;
328 }
329
330 /* Get the mask */
331 psoMask = EBRUSHOBJ_psoMask(pebo);
332 }
333 else
334 {
335 /* Use the Eng function */
336 pfnRealizeBrush = EngRealizeBrush;
337
338 /* We don't handle the mask bitmap here. We do this only on demand */
339 psoMask = NULL;
340 }
341
342 /* Check if this is a hatch brush */
343 if (pbr->flAttrs & BR_IS_HATCH)
344 {
345 /* Get the hatch brush pattern from the PDEV */
346 hbmPattern = (HBITMAP)ppdev->ahsurf[pbr->iHatch];
347 iHatch = pbr->iHatch;
348 }
349 else
350 {
351 /* Use the brushes pattern */
352 hbmPattern = pbr->hbmPattern;
353 iHatch = -1;
354 }
355
356 psurfPattern = SURFACE_ShareLockSurface(hbmPattern);
357 ASSERT(psurfPattern);
358 ASSERT(psurfPattern->ppal);
359
360 /* DIB brushes with DIB_PAL_COLORS usage need a new palette */
361 if (pbr->flAttrs & BR_IS_DIBPALCOLORS)
362 {
363 /* Create a palette with the colors from the DC */
364 ppalPattern = FixupDIBBrushPalette(psurfPattern->ppal, pebo->ppalDC);
365 if (ppalPattern == NULL)
366 {
367 ERR("FixupDIBBrushPalette() failed.\n");
368 return FALSE;
369 }
370
371 pebo->ppalDIB = ppalPattern;
372 }
373 else
374 {
375 /* The palette is already as it should be */
376 ppalPattern = psurfPattern->ppal;
377 }
378
379 /* Initialize XLATEOBJ for the brush */
380 EXLATEOBJ_vInitialize(&exlo,
381 ppalPattern,
382 pebo->psurfTrg->ppal,
383 0,
384 pebo->crCurrentBack,
385 pebo->crCurrentText);
386
387 /* Create the realization */
388 bResult = pfnRealizeBrush(&pebo->BrushObject,
389 &pebo->psurfTrg->SurfObj,
390 &psurfPattern->SurfObj,
391 psoMask,
392 &exlo.xlo,
393 iHatch);
394
395 /* Cleanup the XLATEOBJ */
396 EXLATEOBJ_vCleanup(&exlo);
397
398 /* Unlock surface */
399 SURFACE_ShareUnlockSurface(psurfPattern);
400
401 return bResult;
402 }
403
404 PVOID
405 NTAPI
406 EBRUSHOBJ_pvGetEngBrush(EBRUSHOBJ *pebo)
407 {
408 BOOL bResult;
409
410 if (!pebo->pengbrush)
411 {
412 bResult = EBRUSHOBJ_bRealizeBrush(pebo, FALSE);
413 if (!bResult)
414 {
415 if (pebo->pengbrush)
416 EngDeleteSurface(pebo->pengbrush);
417 pebo->pengbrush = NULL;
418 }
419 }
420
421 return pebo->pengbrush;
422 }
423
424 SURFOBJ*
425 NTAPI
426 EBRUSHOBJ_psoPattern(EBRUSHOBJ *pebo)
427 {
428 PSURFACE psurfPattern;
429
430 psurfPattern = EBRUSHOBJ_pvGetEngBrush(pebo);
431
432 return psurfPattern ? &psurfPattern->SurfObj : NULL;
433 }
434
435 SURFOBJ*
436 NTAPI
437 EBRUSHOBJ_psoMask(EBRUSHOBJ *pebo)
438 {
439 HBITMAP hbmMask;
440 PSURFACE psurfMask;
441 PPDEVOBJ ppdev;
442
443 /* Check if we don't have a mask yet */
444 if (pebo->psoMask == NULL)
445 {
446 /* Check if this is a hatch brush */
447 if (pebo->flattrs & BR_IS_HATCH)
448 {
449 /* Get the PDEV */
450 ppdev = (PPDEVOBJ)pebo->psurfTrg->SurfObj.hdev;
451 if (!ppdev)
452 ppdev = gppdevPrimary;
453
454 /* Use the hatch bitmap as the mask */
455 hbmMask = (HBITMAP)ppdev->ahsurf[pebo->pbrush->iHatch];
456 psurfMask = SURFACE_ShareLockSurface(hbmMask);
457 if (psurfMask == NULL)
458 {
459 ERR("Failed to lock hatch brush for PDEV %p, iHatch %lu\n",
460 ppdev, pebo->pbrush->iHatch);
461 return NULL;
462 }
463
464 NT_ASSERT(psurfMask->SurfObj.iBitmapFormat == BMF_1BPP);
465 pebo->psoMask = &psurfMask->SurfObj;
466 }
467 }
468
469 return pebo->psoMask;
470 }
471
472 /** Exported DDI functions ****************************************************/
473
474 /*
475 * @implemented
476 */
477 PVOID APIENTRY
478 BRUSHOBJ_pvAllocRbrush(
479 IN BRUSHOBJ *pbo,
480 IN ULONG cj)
481 {
482 pbo->pvRbrush = EngAllocMem(0, cj, GDITAG_RBRUSH);
483 return pbo->pvRbrush;
484 }
485
486 /*
487 * @implemented
488 */
489 PVOID APIENTRY
490 BRUSHOBJ_pvGetRbrush(
491 IN BRUSHOBJ *pbo)
492 {
493 EBRUSHOBJ *pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
494 BOOL bResult;
495
496 if (!pbo->pvRbrush)
497 {
498 bResult = EBRUSHOBJ_bRealizeBrush(pebo, TRUE);
499 if (!bResult)
500 {
501 if (pbo->pvRbrush)
502 {
503 EngFreeMem(pbo->pvRbrush);
504 pbo->pvRbrush = NULL;
505 }
506 }
507 }
508
509 return pbo->pvRbrush;
510 }
511
512 /*
513 * @implemented
514 */
515 ULONG APIENTRY
516 BRUSHOBJ_ulGetBrushColor(
517 IN BRUSHOBJ *pbo)
518 {
519 EBRUSHOBJ *pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
520 return pebo->ulRGBColor;
521 }
522
523 /* EOF */