[WIN32K]
[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 #define NDEBUG
13 #include <debug.h>
14
15 static const ULONG gaulHatchBrushes[HS_DDI_MAX][8] =
16 {
17 {0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF}, /* HS_HORIZONTAL */
18 {0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7}, /* HS_VERTICAL */
19 {0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F}, /* HS_FDIAGONAL */
20 {0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE}, /* HS_BDIAGONAL */
21 {0xF7, 0xF7, 0xF7, 0xF7, 0x00, 0xF7, 0xF7, 0xF7}, /* HS_CROSS */
22 {0x7E, 0xBD, 0xDB, 0xE7, 0xE7, 0xDB, 0xBD, 0x7E} /* HS_DIAGCROSS */
23 };
24
25 HSURF gahsurfHatch[HS_DDI_MAX];
26
27 /** Internal functions ********************************************************/
28
29 INIT_FUNCTION
30 NTSTATUS
31 NTAPI
32 InitBrushImpl(VOID)
33 {
34 ULONG i;
35 SIZEL sizl = {8, 8};
36
37 /* Loop all hatch styles */
38 for (i = 0; i < HS_DDI_MAX; i++)
39 {
40 /* Create a default hatch bitmap */
41 gahsurfHatch[i] = (HSURF)EngCreateBitmap(sizl,
42 0,
43 BMF_1BPP,
44 0,
45 (PVOID)gaulHatchBrushes[i]);
46 }
47
48 return STATUS_SUCCESS;
49 }
50
51 VOID
52 NTAPI
53 EBRUSHOBJ_vInit(EBRUSHOBJ *pebo,
54 PBRUSH pbrush,
55 PSURFACE psurf,
56 COLORREF crBackgroundClr,
57 COLORREF crForegroundClr,
58 PPALETTE ppalDC)
59 {
60 ASSERT(pebo);
61 ASSERT(pbrush);
62
63 pebo->BrushObject.flColorType = 0;
64 pebo->BrushObject.pvRbrush = NULL;
65 pebo->pbrush = pbrush;
66 pebo->pengbrush = NULL;
67 pebo->flattrs = pbrush->flAttrs;
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 pebo->crRealize = crColor;
132 pebo->ulRGBColor = crColor;
133
134 /* Initialize an XLATEOBJ RGB -> surface */
135 EXLATEOBJ_vInitialize(&exlo,
136 &gpalRGB,
137 pebo->ppalSurf,
138 pebo->crCurrentBack,
139 0,
140 0);
141
142 /* Translate the brush color to the target format */
143 iSolidColor = XLATEOBJ_iXlate(&exlo.xlo, crColor);
144 pebo->BrushObject.iSolidColor = iSolidColor;
145
146 /* Clean up the XLATEOBJ */
147 EXLATEOBJ_vCleanup(&exlo);
148 }
149
150 VOID
151 NTAPI
152 EBRUSHOBJ_vCleanup(EBRUSHOBJ *pebo)
153 {
154 /* Check if there's a GDI realisation */
155 if (pebo->pengbrush)
156 {
157 /* Unlock the bitmap again */
158 SURFACE_ShareUnlockSurface(pebo->pengbrush);
159 pebo->pengbrush = NULL;
160 }
161
162 /* Check if there's a driver's realisation */
163 if (pebo->BrushObject.pvRbrush)
164 {
165 /* Free allocated driver memory */
166 EngFreeMem(pebo->BrushObject.pvRbrush);
167 pebo->BrushObject.pvRbrush = NULL;
168 }
169
170 /* Dereference the palettes */
171 PALETTE_ShareUnlockPalette(pebo->ppalSurf);
172 PALETTE_ShareUnlockPalette(pebo->ppalDC);
173 if (pebo->ppalDIB) PALETTE_ShareUnlockPalette(pebo->ppalDIB);
174 }
175
176 VOID
177 NTAPI
178 EBRUSHOBJ_vUpdateFromDC(EBRUSHOBJ *pebo,
179 PBRUSH pbrush,
180 PDC pdc)
181 {
182 /* Cleanup the brush */
183 EBRUSHOBJ_vCleanup(pebo);
184
185 /* Reinitialize */
186 EBRUSHOBJ_vInitFromDC(pebo, pbrush, pdc);
187 }
188
189 /**
190 * This function is not exported, because it makes no sense for
191 * The driver to punt back to this function */
192 BOOL
193 APIENTRY
194 EngRealizeBrush(
195 BRUSHOBJ *pbo,
196 SURFOBJ *psoDst,
197 SURFOBJ *psoPattern,
198 SURFOBJ *psoMask,
199 XLATEOBJ *pxlo,
200 ULONG iHatch)
201 {
202 EBRUSHOBJ *pebo;
203 HBITMAP hbmpRealize;
204 SURFOBJ *psoRealize;
205 PSURFACE psurfRealize;
206 POINTL ptlSrc = {0, 0};
207 RECTL rclDest;
208 ULONG lWidth;
209
210 /* Calculate width in bytes of the realized brush */
211 lWidth = WIDTH_BYTES_ALIGN32(psoPattern->sizlBitmap.cx,
212 BitsPerFormat(psoDst->iBitmapFormat));
213
214 /* Allocate a bitmap */
215 hbmpRealize = EngCreateBitmap(psoPattern->sizlBitmap,
216 lWidth,
217 psoDst->iBitmapFormat,
218 BMF_NOZEROINIT,
219 NULL);
220 if (!hbmpRealize)
221 {
222 return FALSE;
223 }
224
225 /* Lock the bitmap */
226 psurfRealize = SURFACE_ShareLockSurface(hbmpRealize);
227
228 /* Already delete the pattern bitmap (will be kept until dereferenced) */
229 EngDeleteSurface((HSURF)hbmpRealize);
230
231 if (!psurfRealize)
232 {
233 return FALSE;
234 }
235
236 /* Copy the bits to the new format bitmap */
237 rclDest.left = rclDest.top = 0;
238 rclDest.right = psoPattern->sizlBitmap.cx;
239 rclDest.bottom = psoPattern->sizlBitmap.cy;
240 psoRealize = &psurfRealize->SurfObj;
241 EngCopyBits(psoRealize, psoPattern, NULL, pxlo, &rclDest, &ptlSrc);
242
243
244 pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
245 pebo->pengbrush = (PVOID)psurfRealize;
246
247 return TRUE;
248 }
249
250 static
251 PPALETTE
252 FixupDIBBrushPalette(
253 _In_ PPALETTE ppalDIB,
254 _In_ PPALETTE ppalDC)
255 {
256 PPALETTE ppalNew;
257 ULONG i, iPalIndex, crColor;
258
259 /* Allocate a new palette */
260 ppalNew = PALETTE_AllocPalette(PAL_INDEXED,
261 ppalDIB->NumColors,
262 NULL,
263 0,
264 0,
265 0);
266
267 /* Loop all colors */
268 for (i = 0; i < ppalDIB->NumColors; i++)
269 {
270 /* Get the RGB color, which is the index into the DC palette */
271 iPalIndex = PALETTE_ulGetRGBColorFromIndex(ppalDIB, i);
272
273 /* Roll over when index is too big */
274 iPalIndex %= ppalDC->NumColors;
275
276 /* Set the indexed DC color as the new color */
277 crColor = PALETTE_ulGetRGBColorFromIndex(ppalDC, iPalIndex);
278 PALETTE_vSetRGBColorForIndex(ppalNew, i, crColor);
279 }
280
281 /* Return the new palette */
282 return ppalNew;
283 }
284
285 BOOL
286 NTAPI
287 EBRUSHOBJ_bRealizeBrush(EBRUSHOBJ *pebo, BOOL bCallDriver)
288 {
289 BOOL bResult;
290 PFN_DrvRealizeBrush pfnRealizeBrush = NULL;
291 PSURFACE psurfPattern, psurfMask;
292 PPDEVOBJ ppdev;
293 EXLATEOBJ exlo;
294 PPALETTE ppalPattern;
295 PBRUSH pbr = pebo->pbrush;
296 HBITMAP hbmPattern;
297 ULONG iHatch;
298
299 /* All EBRUSHOBJs have a surface, see EBRUSHOBJ_vInit */
300 ASSERT(pebo->psurfTrg);
301
302 ppdev = (PPDEVOBJ)pebo->psurfTrg->SurfObj.hdev;
303 if (!ppdev) ppdev = gppdevPrimary;
304
305 if (bCallDriver)
306 pfnRealizeBrush = ppdev->DriverFunctions.RealizeBrush;
307
308 if (!pfnRealizeBrush)
309 pfnRealizeBrush = EngRealizeBrush;
310
311 /* Check if this is a hatch brush */
312 if (pbr->flAttrs & BR_IS_HATCH)
313 {
314 /* Get the hatch brush pattern from the PDEV */
315 hbmPattern = (HBITMAP)ppdev->ahsurf[pbr->ulStyle];
316 iHatch = pbr->ulStyle;
317 }
318 else
319 {
320 /* Use the brushes pattern */
321 hbmPattern = pbr->hbmPattern;
322 iHatch = -1;
323 }
324
325 psurfPattern = SURFACE_ShareLockSurface(hbmPattern);
326 ASSERT(psurfPattern);
327 ASSERT(psurfPattern->ppal);
328
329 /* FIXME: implement mask */
330 psurfMask = NULL;
331
332 /* DIB brushes with DIB_PAL_COLORS usage need a new palette */
333 if (pbr->flAttrs & BR_IS_DIBPALCOLORS)
334 {
335 /* Create a palette with the colors from the DC */
336 ppalPattern = FixupDIBBrushPalette(psurfPattern->ppal, pebo->ppalDC);
337 pebo->ppalDIB = ppalPattern;
338 }
339 else
340 {
341 /* The palette is already as it should be */
342 ppalPattern = psurfPattern->ppal;
343 }
344
345 /* Initialize XLATEOBJ for the brush */
346 EXLATEOBJ_vInitialize(&exlo,
347 ppalPattern,
348 pebo->psurfTrg->ppal,
349 0,
350 pebo->crCurrentBack,
351 pebo->crCurrentText);
352
353 /* Create the realization */
354 bResult = pfnRealizeBrush(&pebo->BrushObject,
355 &pebo->psurfTrg->SurfObj,
356 &psurfPattern->SurfObj,
357 psurfMask ? &psurfMask->SurfObj : NULL,
358 &exlo.xlo,
359 iHatch);
360
361 /* Cleanup the XLATEOBJ */
362 EXLATEOBJ_vCleanup(&exlo);
363
364 /* Unlock surfaces */
365 if (psurfPattern)
366 SURFACE_ShareUnlockSurface(psurfPattern);
367 if (psurfMask)
368 SURFACE_ShareUnlockSurface(psurfMask);
369
370 return bResult;
371 }
372
373 PVOID
374 NTAPI
375 EBRUSHOBJ_pvGetEngBrush(EBRUSHOBJ *pebo)
376 {
377 BOOL bResult;
378
379 if (!pebo->pengbrush)
380 {
381 bResult = EBRUSHOBJ_bRealizeBrush(pebo, FALSE);
382 if (!bResult)
383 {
384 if (pebo->pengbrush)
385 EngDeleteSurface(pebo->pengbrush);
386 pebo->pengbrush = NULL;
387 }
388 }
389
390 return pebo->pengbrush;
391 }
392
393 SURFOBJ*
394 NTAPI
395 EBRUSHOBJ_psoPattern(EBRUSHOBJ *pebo)
396 {
397 PSURFACE psurfPattern;
398
399 psurfPattern = EBRUSHOBJ_pvGetEngBrush(pebo);
400
401 return psurfPattern ? &psurfPattern->SurfObj : NULL;
402 }
403
404
405 /** Exported DDI functions ****************************************************/
406
407 /*
408 * @implemented
409 */
410 PVOID APIENTRY
411 BRUSHOBJ_pvAllocRbrush(
412 IN BRUSHOBJ *pbo,
413 IN ULONG cj)
414 {
415 pbo->pvRbrush = EngAllocMem(0, cj, GDITAG_RBRUSH);
416 return pbo->pvRbrush;
417 }
418
419 /*
420 * @implemented
421 */
422 PVOID APIENTRY
423 BRUSHOBJ_pvGetRbrush(
424 IN BRUSHOBJ *pbo)
425 {
426 EBRUSHOBJ *pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
427 BOOL bResult;
428
429 if (!pbo->pvRbrush)
430 {
431 bResult = EBRUSHOBJ_bRealizeBrush(pebo, TRUE);
432 if (!bResult)
433 {
434 if (pbo->pvRbrush)
435 {
436 EngFreeMem(pbo->pvRbrush);
437 pbo->pvRbrush = NULL;
438 }
439 }
440 }
441
442 return pbo->pvRbrush;
443 }
444
445 /*
446 * @implemented
447 */
448 ULONG APIENTRY
449 BRUSHOBJ_ulGetBrushColor(
450 IN BRUSHOBJ *pbo)
451 {
452 EBRUSHOBJ *pebo = CONTAINING_RECORD(pbo, EBRUSHOBJ, BrushObject);
453 return pebo->ulRGBColor;
454 }
455
456 /* EOF */