32d50fba726057b4762cc1b6749e2e275d4a59d3
[wine/hacks.git] / dlls / winedib.drv / pen_brush.c
blob32d50fba726057b4762cc1b6749e2e275d4a59d3
1 /*
2 * DIBDRV pen objects
4 * Copyright 2009 Massimo Del Fedele
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include "dibdrv.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(dibdrv);
29 static const DASHPATTERN dashPatterns[4] =
31 {2, {18, 6}},
32 {2, {3, 3}},
33 {4, {9, 6, 3, 6}},
34 {6, {9, 3, 3, 3, 3, 3}}
37 static inline void OrderEndPoints(int *s, int *e)
39 if(*s > *e)
41 int tmp;
42 tmp = *s + 1;
43 *s = *e + 1;
44 *e = tmp;
48 static void SolidPenHLine(DIBDRVPHYSDEV *physDev, int x1, int x2, int y)
50 OrderEndPoints(&x1, &x2);
51 physDev->physBitmap->funcs->SolidHLine(physDev->physBitmap, x1, x2, y, physDev->penAnd, physDev->penXor);
54 static void SolidPenVLine(DIBDRVPHYSDEV *physDev, int x, int y1, int y2)
56 OrderEndPoints(&y1, &y2);
57 physDev->physBitmap->funcs->SolidVLine(physDev->physBitmap, x, y1, y2, physDev->penAnd, physDev->penXor);
60 static void WINAPI SolidPenLineCallback(int x, int y, LPARAM lparam)
62 DIBDRVPHYSDEV *physDev = (DIBDRVPHYSDEV *)lparam;
64 physDev->physBitmap->funcs->SetPixel(physDev->physBitmap, x, y, physDev->penAnd, physDev->penXor);
65 return;
68 static void SolidPenLine(DIBDRVPHYSDEV *physDev, int x1, int y1, int x2, int y2)
70 LineDDA(x1, y1, x2, y2, SolidPenLineCallback, (LPARAM)physDev);
73 static inline void GetDashColors(DIBDRVPHYSDEV *physDev, DWORD *and, DWORD *xor)
75 if(physDev->markSpace == mark)
77 *and = physDev->penAnd;
78 *xor = physDev->penXor;
80 else if(GetBkMode(physDev->hdc) == OPAQUE)
82 *and = physDev->backgroundAnd;
83 *xor = physDev->backgroundXor;
85 else
87 *and = 0xffffffff;
88 *xor = 0;
92 static inline void NextDash(DIBDRVPHYSDEV *physDev)
94 if(physDev->leftInDash != 0)
95 return;
97 physDev->curDash++;
98 if(physDev->curDash == physDev->penPattern->count)
99 physDev->curDash = 0;
100 physDev->leftInDash = physDev->penPattern->dashes[physDev->curDash];
101 if(physDev->markSpace == mark)
102 physDev->markSpace = space;
103 else
104 physDev->markSpace = mark;
107 static void DashedPenHLine(DIBDRVPHYSDEV *physDev, int x1, int x2, int y)
109 int x = x1;
110 DWORD and, xor;
111 DWORD dashLen;
113 if(x1 <= x2)
115 while(x != x2)
117 GetDashColors(physDev, &and, &xor);
119 dashLen = physDev->leftInDash;
120 if(x + dashLen > x2)
121 dashLen = x2 - x;
123 physDev->physBitmap->funcs->SolidHLine(physDev->physBitmap, x, x + dashLen, y, and, xor);
124 x += dashLen;
126 physDev->leftInDash -= dashLen;
127 NextDash(physDev);
130 else
132 while(x != x2)
134 GetDashColors(physDev, &and, &xor);
136 dashLen = physDev->leftInDash;
137 if(x - (int)dashLen < x2)
138 dashLen = x - x2;
140 physDev->physBitmap->funcs->SolidHLine(physDev->physBitmap, x - dashLen + 1, x + 1, y, and, xor);
141 x -= dashLen;
143 physDev->leftInDash -= dashLen;
144 NextDash(physDev);
149 static void DashedPenVLine(DIBDRVPHYSDEV *physDev, int x, int y1, int y2)
151 int y = y1;
152 DWORD and, xor;
153 DWORD dashLen;
155 if(y1 <= y2)
157 while(y != y2)
159 GetDashColors(physDev, &and, &xor);
161 dashLen = physDev->leftInDash;
162 if(y + dashLen > y2)
163 dashLen = y2 - y;
165 physDev->physBitmap->funcs->SolidVLine(physDev->physBitmap, x, y, y + dashLen, and, xor);
166 y += dashLen;
168 physDev->leftInDash -= dashLen;
169 NextDash(physDev);
172 else
174 while(y != y2)
176 GetDashColors(physDev, &and, &xor);
178 dashLen = physDev->leftInDash;
179 if(y - (int)dashLen < y2)
180 dashLen = y - y2;
182 physDev->physBitmap->funcs->SolidVLine(physDev->physBitmap, x, y - dashLen + 1, y + 1, and, xor);
183 y -= dashLen;
185 physDev->leftInDash -= dashLen;
186 NextDash(physDev);
191 static void WINAPI DashedPenLineCallback(int x, int y, LPARAM lparam)
193 DIBDRVPHYSDEV *physDev = (DIBDRVPHYSDEV *)lparam;
194 DWORD and, xor;
196 GetDashColors(physDev, &and, &xor);
198 physDev->physBitmap->funcs->SetPixel(physDev->physBitmap, x, y, and, xor);
200 physDev->leftInDash--;
201 NextDash(physDev);
203 return;
206 static void DashedPenLine(DIBDRVPHYSDEV *physDev, int x1, int y1, int x2, int y2)
208 LineDDA(x1, y1, x2, y2, DashedPenLineCallback, (LPARAM)physDev);
211 void _DIBDRV_ResetDashOrigin(DIBDRVPHYSDEV *physDev)
213 physDev->curDash = 0;
214 if(physDev->penPattern)
215 physDev->leftInDash = physDev->penPattern->dashes[0];
216 physDev->markSpace = mark;
219 #if 0
220 /* For 1bpp bitmaps, unless the selected foreground color exactly
221 matches foreground's colortable OR it's the WHITE color,
222 the background color is used -- tested on WinXP */
223 static DWORD AdjustFgColor(DIBDRVPHYSDEV *physDev, COLORREF color)
225 RGBQUAD *back = physDev->physBitmap->colorTable;
226 RGBQUAD *fore = physDev->physBitmap->colorTable+1;
229 fore->rgbRed == GetRValue(color) &&
230 fore->rgbGreen == GetGValue(color) &&
231 fore->rgbBlue == GetBValue(color))
232 return 1;
233 else if(
234 back->rgbRed == GetRValue(color) &&
235 back->rgbGreen == GetGValue(color) &&
236 back->rgbBlue == GetBValue(color))
237 return 0;
238 else if((color & 0x00ffffff) == 0x00ffffff)
239 return 1;
240 else
241 return 0;
244 static void FixupFgColors1(DIBDRVPHYSDEV *physDev)
246 int rop = GetROP2(physDev->hdc);
248 physDev->penColor = AdjustFgColor(physDev, physDev->penColorref);
249 physDev->brushColor = AdjustFgColor(physDev, physDev->brushColorref);
251 _DIBDRV_CalcAndXorMasks(rop, physDev->penColor, &physDev->penAnd, &physDev->penXor);
252 _DIBDRV_CalcAndXorMasks(rop, physDev->brushColor, &physDev->brushAnd, &physDev->brushXor);
253 HeapFree(GetProcessHeap(), 0, physDev->brushAnds);
254 HeapFree(GetProcessHeap(), 0, physDev->brushXors);
255 physDev->brushAnds = NULL;
256 physDev->brushXors = NULL;
258 #endif
260 #if 0
261 /* For 1bpp bitmaps, unless the selected foreground color exactly
262 matches one of the colors in the colortable, then the color that
263 isn't the bkgnd color is used. */
264 static DWORD AdjustFgColor(DIBDRVPHYSDEV *physDev, COLORREF color)
266 RGBQUAD rgb;
267 int i;
269 rgb.rgbRed = GetRValue(color);
270 rgb.rgbGreen = GetGValue(color);
271 rgb.rgbBlue = GetBValue(color);
273 for(i = 0; i < physDev->physBitmap->colorTableSize; i++)
275 RGBQUAD *cur = physDev->physBitmap->colorTable + i;
276 if((rgb.rgbRed == cur->rgbRed) && (rgb.rgbGreen == cur->rgbGreen) && (rgb.rgbBlue == cur->rgbBlue))
277 return i;
279 return ~physDev->backgroundColor & 1;
282 static void FixupFgColors1(DIBDRVPHYSDEV *physDev)
284 int rop = GetROP2(physDev->hdc);
286 physDev->penColor = AdjustFgColor(physDev, physDev->penColorref);
287 physDev->brushColor = AdjustFgColor(physDev, physDev->brushColorref);
289 _DIBDRV_CalcAndXorMasks(rop, physDev->penColor, &physDev->penAnd, &physDev->penXor);
290 _DIBDRV_CalcAndXorMasks(rop, physDev->brushColor, &physDev->brushAnd, &physDev->brushXor);
291 HeapFree(GetProcessHeap(), 0, physDev->brushAnds);
292 HeapFree(GetProcessHeap(), 0, physDev->brushXors);
293 physDev->brushAnds = NULL;
294 physDev->brushXors = NULL;
296 #endif
298 static void SolidBrushHLine(DIBDRVPHYSDEV *physDev, int x1, int x2, int y)
300 OrderEndPoints(&x1, &x2);
301 physDev->physBitmap->funcs->SolidHLine(physDev->physBitmap, x1, x2, y, physDev->brushAnd, physDev->brushXor);
305 static void GenerateMasks(DIBDRVPHYSDEV *physDev, DIBDRVBITMAP *bmp, DWORD **and, DWORD **xor)
307 int rop = GetROP2(physDev->hdc);
308 DWORD *color_ptr, *and_ptr, *xor_ptr;
309 DWORD size = bmp->height * abs(bmp->stride);
311 *and = HeapAlloc(GetProcessHeap(), 0, size);
312 *xor = HeapAlloc(GetProcessHeap(), 0, size);
314 color_ptr = bmp->bits;
315 and_ptr = *and;
316 xor_ptr = *xor;
318 while(size)
320 _DIBDRV_CalcAndXorMasks(rop, *color_ptr++, and_ptr++, xor_ptr++);
321 size -= 4;
325 static void PatternBrushHLine(DIBDRVPHYSDEV *physDev, int x1, int x2, int y)
327 DWORD *and, *xor, brushY = y % physDev->brushBitmap->height;
329 if(!physDev->brushAnds)
330 GenerateMasks(physDev, physDev->brushBitmap, &physDev->brushAnds, &physDev->brushXors);
332 OrderEndPoints(&x1, &x2);
333 and = (DWORD *)((char *)physDev->brushAnds + brushY * physDev->brushBitmap->stride);
334 xor = (DWORD *)((char *)physDev->brushXors + brushY * physDev->brushBitmap->stride);
336 physDev->physBitmap->funcs->PatternHLine(physDev->physBitmap, x1, x2, y, and, xor, physDev->brushBitmap->width, x1 % physDev->brushBitmap->width);
339 /* null function for PS_NULL and BS_NULL pen and brush styles */
340 void NullPenHLine(DIBDRVPHYSDEV *physDev, int x1, int x2, int y) {}
341 void NullPenVLine(DIBDRVPHYSDEV *physDev, int x, int y1, int y2) {}
342 void NullPenLine(DIBDRVPHYSDEV *physDev, int x1, int y1, int x2, int y2) {}
343 void NullBrushHLine(DIBDRVPHYSDEV *physDev, int x1, int x2, int y) {}
345 /***********************************************************************
346 * DIBDRV_SelectPen
348 HPEN DIBDRV_SelectPen( DIBDRVPHYSDEV *physDev, HPEN hpen )
350 HPEN res;
351 LOGPEN logpen;
353 MAYBE(TRACE("physDev:%p, hpen:%p\n", physDev, hpen));
355 if(physDev->hasDIB)
357 GetObjectW(hpen, sizeof(logpen), &logpen);
359 physDev->penColorref = logpen.lopnColor;
360 physDev->penColor = physDev->physBitmap->funcs->ColorToPixel(
361 physDev->physBitmap,
362 _DIBDRV_MapColor(physDev, physDev->penColorref));
364 _DIBDRV_CalcAndXorMasks(GetROP2(physDev->hdc), physDev->penColor, &physDev->penAnd, &physDev->penXor);
366 physDev->penStyle = logpen.lopnStyle;
367 switch(logpen.lopnStyle)
369 default:
370 ONCE(FIXME("Unhandled pen style %d\n", logpen.lopnStyle));
371 physDev->penStyle = PS_SOLID;
372 /* fall through */
373 case PS_SOLID:
374 physDev->penHLine = SolidPenHLine;
375 physDev->penVLine = SolidPenVLine;
376 physDev->penLine = SolidPenLine;
377 physDev->penPattern = NULL;
378 break;
380 case PS_DASH:
381 case PS_DOT:
382 case PS_DASHDOT:
383 case PS_DASHDOTDOT:
384 physDev->penHLine = DashedPenHLine;
385 physDev->penVLine = DashedPenVLine;
386 physDev->penLine = DashedPenLine;
387 physDev->penPattern = &dashPatterns[logpen.lopnStyle - PS_DASH];
388 _DIBDRV_ResetDashOrigin(physDev);
389 break;
390 case PS_NULL:
391 physDev->penHLine = NullPenHLine;
392 physDev->penVLine = NullPenVLine;
393 physDev->penLine = NullPenLine;
394 physDev->penPattern = NULL;
395 break;
397 res = hpen;
399 else
401 /* DDB selected in, use X11 driver */
402 res = _DIBDRV_GetDisplayDriver()->pSelectPen(physDev->X11PhysDev, hpen);
404 return res;
407 /***********************************************************************
408 * DIBDRV_SetDCPenColor
410 COLORREF DIBDRV_SetDCPenColor( DIBDRVPHYSDEV *physDev, COLORREF crColor )
412 COLORREF res;
414 MAYBE(TRACE("physDev:%p, crColor:%x\n", physDev, crColor));
416 if(physDev->hasDIB)
418 /* DIB section selected in, use DIB Engine */
419 ONCE(FIXME("STUB\n"));
420 res = crColor;
422 else
424 /* DDB selected in, use X11 driver */
425 res = _DIBDRV_GetDisplayDriver()->pSetDCPenColor(physDev->X11PhysDev, crColor);
427 return res;
430 /***********************************************************************
431 * DIBDRV_SelectBrush
433 HBRUSH DIBDRV_SelectBrush( DIBDRVPHYSDEV *physDev, HBRUSH hbrush )
435 HBRUSH res = hbrush;
436 LOGBRUSH logbrush;
439 MAYBE(TRACE("physDev:%p, hbrush:%p\n", physDev, hbrush));
441 if(physDev->hasDIB)
443 GetObjectW(hbrush, sizeof(logbrush), &logbrush);
445 /* frees any currently selected DIB brush and cache */
446 _DIBDRVBITMAP_Free(physDev->brushBitmap);
447 physDev->brushBitmap = NULL;
448 _DIBDRVBITMAP_Free(physDev->brushBmpCache);
449 physDev->brushBmpCache = NULL;
450 if(physDev->brushAnds)
452 HeapFree(GetProcessHeap(), 0, physDev->brushAnds);
453 HeapFree(GetProcessHeap(), 0, physDev->brushXors);
455 physDev->brushAnds = NULL;
456 physDev->brushXors = NULL;
458 switch (logbrush.lbStyle)
460 default:
461 FIXME("Unhandled brush style %d\n", logbrush.lbStyle);
462 physDev->brushColorref = 0;
463 goto solid;
465 case BS_SOLID:
466 physDev->brushColorref = logbrush.lbColor;
467 solid:
468 MAYBE(TRACE("SOLID Pattern -- color is %x\n", physDev->brushColorref));
469 physDev->brushStyle = BS_SOLID;
470 physDev->brushHLine = SolidBrushHLine;
472 physDev->brushColor = physDev->physBitmap->funcs->ColorToPixel(
473 physDev->physBitmap,
474 _DIBDRV_MapColor(physDev, physDev->brushColorref));
476 _DIBDRV_CalcAndXorMasks(physDev->rop2, physDev->brushColor,
477 &physDev->brushAnd, &physDev->brushXor);
479 /* set the physDev brush style */
480 physDev->brushStyle = BS_SOLID;
481 physDev->isBrushBitmap = FALSE;
483 break;
485 case BS_DIBPATTERN8X8:
486 case BS_DIBPATTERN:
488 DIBDRVBITMAP src;
489 BITMAPINFO *bmi;
491 FIXME("DIB Pattern\n");
493 /* if no DIB selected in, fallback to null brush */
494 if(!physDev->physBitmap->bits)
496 physDev->brushColorref = 0;
497 goto solid;
500 /* gets brush DIB's pointer */
501 bmi = GlobalLock16(logbrush.lbHatch);
503 /* initializes a temporary DIB with brush's one */
504 if(!_DIBDRVBITMAP_InitFromBitmapinfo(&src, bmi, NULL))
506 ERR("Failed to initialize brush DIB\n");
507 res = 0;
508 goto err;
511 /* converts brush bitmap to match currently selected one's format */
512 if(!_DIBDRVBITMAP_Convert(physDev->brushBitmap, &src, physDev->physBitmap))
514 ERR("Failed to convert brush DIB\n");
515 _DIBDRVBITMAP_Free(&src);
516 res = 0;
517 goto err;
520 /* frees temporary DIB's data */
521 _DIBDRVBITMAP_Free(&src);
523 /* use DIB pattern for brush lines */
524 physDev->brushHLine = PatternBrushHLine;
526 err:
527 /* frees brush's DIB pointer */
528 GlobalUnlock16(logbrush.lbHatch);
530 break;
532 case BS_DIBPATTERNPT:
533 FIXME("BS_DIBPATTERNPT not supported\n");
534 physDev->brushColorref = 0;
535 goto solid;
537 case BS_HATCHED:
538 FIXME("BS_HATCHED not supported\n");
539 physDev->brushColorref = 0;
540 goto solid;
542 case BS_NULL:
544 MAYBE(TRACE("NULL Pattern\n"));
545 physDev->brushColorref = 0;
546 physDev->brushColor = physDev->physBitmap->funcs->ColorToPixel(
547 physDev->physBitmap,
548 _DIBDRV_MapColor(physDev, 0));
549 physDev->brushHLine = NullBrushHLine;
550 break;
553 case BS_PATTERN:
554 case BS_PATTERN8X8:
555 FIXME("BS_PATTERN not supported\n");
556 physDev->brushColorref = 0;
557 goto solid;
560 MAYBE(TRACE("END\n"));
561 return hbrush;
563 else
565 /* DDB selected in, use X11 driver */
567 /* we must check if a DIB pattern is requested */
568 GetObjectW(hbrush, sizeof(logbrush), &logbrush);
569 switch (logbrush.lbStyle)
571 case BS_DIBPATTERN8X8:
572 case BS_DIBPATTERN:
573 case BS_DIBPATTERNPT:
574 FIXME("A DIB pattern was requested for a DDB bitmap\n");
575 break;
577 case BS_SOLID:
578 case BS_HATCHED:
579 case BS_NULL:
580 case BS_PATTERN:
581 case BS_PATTERN8X8:
582 default:
583 break;
585 res = _DIBDRV_GetDisplayDriver()->pSelectBrush(physDev->X11PhysDev, hbrush);
587 return res;
590 /***********************************************************************
591 * DIBDRV_SetDCBrushColor
593 COLORREF DIBDRV_SetDCBrushColor( DIBDRVPHYSDEV *physDev, COLORREF crColor )
595 COLORREF res;
597 MAYBE(TRACE("physDev:%p, crColor:%x\n", physDev, crColor));
599 if(physDev->hasDIB)
601 /* DIB section selected in, use DIB Engine */
602 ONCE(FIXME("STUB\n"));
603 res = crColor;
605 else
607 /* DDB selected in, use X11 driver */
608 res = _DIBDRV_GetDisplayDriver()->pSetDCBrushColor(physDev->X11PhysDev, crColor);
610 return res;
613 /***********************************************************************
614 * SetROP2
616 int DIBDRV_SetROP2( DIBDRVPHYSDEV *physDev, int rop )
618 int prevRop;
620 MAYBE(TRACE("physDev:%p, rop:%x\n", physDev, rop));
622 prevRop = physDev->rop2;
623 physDev->rop2 = rop;
625 if(prevRop != rop)
627 _DIBDRV_CalcAndXorMasks(rop, physDev->penColor, &physDev->penAnd, &physDev->penXor);
628 _DIBDRV_CalcAndXorMasks(rop, physDev->brushColor, &physDev->brushAnd, &physDev->brushXor);
629 _DIBDRV_CalcAndXorMasks(rop, physDev->backgroundColor, &physDev->backgroundAnd, &physDev->backgroundXor);
630 if(physDev->brushAnds)
632 HeapFree(GetProcessHeap(), 0, physDev->brushAnds);
633 HeapFree(GetProcessHeap(), 0, physDev->brushXors);
635 physDev->brushAnds = NULL;
636 physDev->brushXors = NULL;
639 return prevRop;
640 /* note : X11 Driver don't have SetROP2() function exported */
643 /***********************************************************************
644 * SetBkColor
646 COLORREF DIBDRV_SetBkColor( DIBDRVPHYSDEV *physDev, COLORREF color )
648 COLORREF res;
650 MAYBE(TRACE("physDev:%p, color:%x\n", physDev, color));
652 if(physDev->hasDIB)
654 physDev->backgroundColor = _DIBDRV_MapColor(physDev, color);
655 physDev->backgroundColor = physDev->physBitmap->funcs->ColorToPixel(physDev->physBitmap, physDev->backgroundColor);
657 _DIBDRV_CalcAndXorMasks(physDev->rop2, physDev->backgroundColor, &physDev->backgroundAnd, &physDev->backgroundXor);
659 res = TRUE;
661 else
663 /* DDB selected in, use X11 driver */
664 res = _DIBDRV_GetDisplayDriver()->pSetBkColor(physDev->X11PhysDev, color);
666 return res;