DIB Engine: fixes against wine tests
[wine/hacks.git] / dlls / winedib.drv / pen_brush.c
blobc40bfaf326e19aedbdeccfbb00d260f17bf76aaa
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 = _DIBDRV_MapColor(physDev, logpen.lopnColor);
360 physDev->penColor = physDev->physBitmap.funcs->ColorToPixel(&physDev->physBitmap, physDev->penColorref);
362 _DIBDRV_CalcAndXorMasks(GetROP2(physDev->hdc), physDev->penColor, &physDev->penAnd, &physDev->penXor);
364 physDev->penStyle = logpen.lopnStyle;
365 switch(logpen.lopnStyle)
367 default:
368 ONCE(FIXME("Unhandled pen style %d\n", logpen.lopnStyle));
369 physDev->penStyle = PS_SOLID;
370 /* fall through */
371 case PS_SOLID:
372 physDev->penHLine = SolidPenHLine;
373 physDev->penVLine = SolidPenVLine;
374 physDev->penLine = SolidPenLine;
375 physDev->penPattern = NULL;
376 break;
378 case PS_DASH:
379 case PS_DOT:
380 case PS_DASHDOT:
381 case PS_DASHDOTDOT:
382 physDev->penHLine = DashedPenHLine;
383 physDev->penVLine = DashedPenVLine;
384 physDev->penLine = DashedPenLine;
385 physDev->penPattern = &dashPatterns[logpen.lopnStyle - PS_DASH];
386 _DIBDRV_ResetDashOrigin(physDev);
387 break;
388 case PS_NULL:
389 physDev->penHLine = NullPenHLine;
390 physDev->penVLine = NullPenVLine;
391 physDev->penLine = NullPenLine;
392 physDev->penPattern = NULL;
393 break;
395 res = hpen;
397 else
399 /* DDB selected in, use X11 driver */
400 res = _DIBDRV_GetDisplayDriver()->pSelectPen(physDev->X11PhysDev, hpen);
402 return res;
405 /***********************************************************************
406 * DIBDRV_SetDCPenColor
408 COLORREF DIBDRV_SetDCPenColor( DIBDRVPHYSDEV *physDev, COLORREF crColor )
410 COLORREF res;
412 MAYBE(TRACE("physDev:%p, crColor:%x\n", physDev, crColor));
414 if(physDev->hasDIB)
416 /* DIB section selected in, use DIB Engine */
417 ONCE(FIXME("STUB\n"));
418 res = crColor;
420 else
422 /* DDB selected in, use X11 driver */
423 res = _DIBDRV_GetDisplayDriver()->pSetDCPenColor(physDev->X11PhysDev, crColor);
425 return res;
428 /***********************************************************************
429 * DIBDRV_SelectBrush
431 HBRUSH DIBDRV_SelectBrush( DIBDRVPHYSDEV *physDev, HBRUSH hbrush )
433 HBRUSH res = hbrush;
434 LOGBRUSH logbrush;
437 MAYBE(TRACE("physDev:%p, hbrush:%p\n", physDev, hbrush));
439 if(physDev->hasDIB)
441 GetObjectW(hbrush, sizeof(logbrush), &logbrush);
443 /* frees any currently selected DIB brush and cache */
444 _DIBDRVBITMAP_Free(&physDev->brushBitmap);
445 _DIBDRVBITMAP_Free(&physDev->brushBmpCache);
446 if(physDev->brushAnds)
448 HeapFree(GetProcessHeap(), 0, physDev->brushAnds);
449 HeapFree(GetProcessHeap(), 0, physDev->brushXors);
451 physDev->brushAnds = NULL;
452 physDev->brushXors = NULL;
454 switch (logbrush.lbStyle)
456 default:
457 FIXME("Unhandled brush style %d\n", logbrush.lbStyle);
458 physDev->brushColorref = 0;
459 goto solid;
461 case BS_SOLID:
462 physDev->brushColorref = _DIBDRV_MapColor(physDev, logbrush.lbColor);
463 solid:
464 MAYBE(TRACE("SOLID Pattern -- color is %x\n", physDev->brushColorref));
465 physDev->brushStyle = BS_SOLID;
466 physDev->brushHLine = SolidBrushHLine;
468 physDev->brushColor = physDev->physBitmap.funcs->ColorToPixel(&physDev->physBitmap, physDev->brushColorref);
470 _DIBDRV_CalcAndXorMasks(physDev->rop2, physDev->brushColor,
471 &physDev->brushAnd, &physDev->brushXor);
473 /* set the physDev brush style */
474 physDev->brushStyle = BS_SOLID;
475 physDev->isBrushBitmap = FALSE;
477 break;
479 case BS_DIBPATTERN8X8:
480 case BS_DIBPATTERN:
482 DIBDRVBITMAP src;
483 BITMAPINFO *bmi;
485 FIXME("DIB Pattern\n");
487 /* if no DIB selected in, fallback to null brush */
488 if(!physDev->physBitmap.bits)
490 physDev->brushColorref = 0;
491 goto solid;
494 /* gets brush DIB's pointer */
495 bmi = GlobalLock16(logbrush.lbHatch);
497 /* initializes a temporary DIB with brush's one */
498 if(!_DIBDRVBITMAP_InitFromBitmapinfo(&src, bmi))
500 ERR("Failed to initialize brush DIB\n");
501 res = 0;
502 goto err;
505 /* converts brush bitmap to match currently selected one's format */
506 if(!_DIBDRVBITMAP_Convert(&physDev->brushBitmap, &src, &physDev->physBitmap))
508 ERR("Failed to convert brush DIB\n");
509 _DIBDRVBITMAP_Free(&src);
510 res = 0;
511 goto err;
514 /* frees temporary DIB's data */
515 _DIBDRVBITMAP_Free(&src);
517 /* use DIB pattern for brush lines */
518 physDev->brushHLine = PatternBrushHLine;
520 err:
521 /* frees brush's DIB pointer */
522 GlobalUnlock16(logbrush.lbHatch);
524 break;
526 case BS_DIBPATTERNPT:
527 FIXME("BS_DIBPATTERNPT not supported\n");
528 physDev->brushColorref = 0;
529 goto solid;
531 case BS_HATCHED:
532 FIXME("BS_HATCHED not supported\n");
533 physDev->brushColorref = 0;
534 goto solid;
536 case BS_NULL:
538 MAYBE(TRACE("NULL Pattern\n"));
539 physDev->brushColorref = 0;
540 physDev->brushColor = physDev->physBitmap.funcs->ColorToPixel(&physDev->physBitmap, 0);
541 physDev->brushHLine = NullBrushHLine;
542 break;
545 case BS_PATTERN:
546 case BS_PATTERN8X8:
547 FIXME("BS_PATTERN not supported\n");
548 physDev->brushColorref = 0;
549 goto solid;
552 MAYBE(TRACE("END\n"));
553 return hbrush;
555 else
557 /* DDB selected in, use X11 driver */
559 /* we must check if a DIB pattern is requested */
560 GetObjectW(hbrush, sizeof(logbrush), &logbrush);
561 switch (logbrush.lbStyle)
563 case BS_DIBPATTERN8X8:
564 case BS_DIBPATTERN:
565 case BS_DIBPATTERNPT:
566 FIXME("A DIB pattern was requested for a DDB bitmap\n");
567 break;
569 case BS_SOLID:
570 case BS_HATCHED:
571 case BS_NULL:
572 case BS_PATTERN:
573 case BS_PATTERN8X8:
574 default:
575 break;
577 res = _DIBDRV_GetDisplayDriver()->pSelectBrush(physDev->X11PhysDev, hbrush);
579 return res;
582 /***********************************************************************
583 * DIBDRV_SetDCBrushColor
585 COLORREF DIBDRV_SetDCBrushColor( DIBDRVPHYSDEV *physDev, COLORREF crColor )
587 COLORREF res;
589 MAYBE(TRACE("physDev:%p, crColor:%x\n", physDev, crColor));
591 if(physDev->hasDIB)
593 /* DIB section selected in, use DIB Engine */
594 ONCE(FIXME("STUB\n"));
595 res = crColor;
597 else
599 /* DDB selected in, use X11 driver */
600 res = _DIBDRV_GetDisplayDriver()->pSetDCBrushColor(physDev->X11PhysDev, crColor);
602 return res;
605 /***********************************************************************
606 * SetROP2
608 int DIBDRV_SetROP2( DIBDRVPHYSDEV *physDev, int rop )
610 int prevRop;
612 MAYBE(TRACE("physDev:%p, rop:%x\n", physDev, rop));
614 prevRop = physDev->rop2;
615 physDev->rop2 = rop;
617 if(prevRop != rop)
619 _DIBDRV_CalcAndXorMasks(rop, physDev->penColor, &physDev->penAnd, &physDev->penXor);
620 _DIBDRV_CalcAndXorMasks(rop, physDev->brushColor, &physDev->brushAnd, &physDev->brushXor);
621 _DIBDRV_CalcAndXorMasks(rop, physDev->backgroundColor, &physDev->backgroundAnd, &physDev->backgroundXor);
622 if(physDev->brushAnds)
624 HeapFree(GetProcessHeap(), 0, physDev->brushAnds);
625 HeapFree(GetProcessHeap(), 0, physDev->brushXors);
627 physDev->brushAnds = NULL;
628 physDev->brushXors = NULL;
631 return prevRop;
632 /* note : X11 Driver don't have SetROP2() function exported */
635 /***********************************************************************
636 * SetBkColor
638 COLORREF DIBDRV_SetBkColor( DIBDRVPHYSDEV *physDev, COLORREF color )
640 COLORREF res;
642 MAYBE(TRACE("physDev:%p, color:%x\n", physDev, color));
644 if(physDev->hasDIB)
646 physDev->backgroundColor = _DIBDRV_MapColor(physDev, color);
647 physDev->backgroundColor = physDev->physBitmap.funcs->ColorToPixel(&physDev->physBitmap, physDev->backgroundColor);
649 _DIBDRV_CalcAndXorMasks(physDev->rop2, physDev->backgroundColor, &physDev->backgroundAnd, &physDev->backgroundXor);
651 res = TRUE;
653 else
655 /* DDB selected in, use X11 driver */
656 res = _DIBDRV_GetDisplayDriver()->pSetBkColor(physDev->X11PhysDev, color);
658 return res;