1. implemented hatched brushes
[reactos.git] / reactos / subsys / win32k / dib / dib1bpp.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: dib1bpp.c,v 1.25 2004/04/25 11:34:12 weiden Exp $ */
20
21 #undef WIN32_LEAN_AND_MEAN
22 #include <windows.h>
23 #include <stdlib.h>
24 #include <win32k/bitmaps.h>
25 #include <win32k/brush.h>
26 #include <win32k/debug.h>
27 #include <include/object.h>
28 #include <debug.h>
29 #include <ddk/winddi.h>
30 #include "../eng/objects.h"
31 #include "dib.h"
32
33 VOID
34 DIB_1BPP_PutPixel(SURFOBJ *SurfObj, LONG x, LONG y, ULONG c)
35 {
36 PBYTE addr = SurfObj->pvScan0 + y * SurfObj->lDelta + (x >> 3);
37
38 if ( !c )
39 *addr &= ~MASK1BPP(x);
40 else
41 *addr |= MASK1BPP(x);
42 }
43
44 ULONG
45 DIB_1BPP_GetPixel(SURFOBJ *SurfObj, LONG x, LONG y)
46 {
47 PBYTE addr = SurfObj->pvScan0 + y * SurfObj->lDelta + (x >> 3);
48
49 return (*addr & MASK1BPP(x) ? 1 : 0);
50 }
51
52 VOID
53 DIB_1BPP_HLine(SURFOBJ *SurfObj, LONG x1, LONG x2, LONG y, ULONG c)
54 {
55 while(x1 < x2) {
56 DIB_1BPP_PutPixel(SurfObj, x1, y, c);
57 x1++;
58 }
59 }
60
61 VOID
62 DIB_1BPP_VLine(SURFOBJ *SurfObj, LONG x, LONG y1, LONG y2, ULONG c)
63 {
64 while(y1 < y2) {
65 DIB_1BPP_PutPixel(SurfObj, x, y1, c);
66 y1++;
67 }
68 }
69
70 static
71 void
72 DIB_1BPP_BitBltSrcCopy_From1BPP (
73 SURFOBJ* DestSurf, SURFOBJ* SourceSurf,
74 PRECTL DestRect, POINTL *SourcePoint )
75 {
76 // the 'window' in this sense is the x-position that corresponds
77 // to the left-edge of the 8-pixel byte we are currently working with.
78 // dwx is current x-window, dwx2 is the 'last' window we need to process
79 int dwx, dwx2; // destination window x-position
80 int swx; // source window y-position
81
82 // left and right edges of source and dest rectangles
83 int dl = DestRect->left; // dest left
84 int dr = DestRect->right-1; // dest right (inclusive)
85 int sl = SourcePoint->x; // source left
86 int sr = sl + dr - dl; // source right (inclusive)
87
88 // which direction are we going?
89 int xinc;
90 int yinc;
91
92 // following 4 variables are used for the y-sweep
93 int dy; // dest y
94 int dy1; // dest y start
95 int dy2; // dest y end
96 int sy1; // src y start
97
98 int shift;
99 BYTE srcmask, dstmask;
100
101 // 'd' and 's' are the dest & src buffer pointers that I use on my x-sweep
102 // 'pd' and 'ps' are the dest & src buffer pointers used on the inner y-sweep
103 PBYTE d, pd; // dest ptrs
104 PBYTE s, ps; // src ptrs
105
106 shift = (dl-sl)&7;
107
108 if ( DestRect->top <= SourcePoint->y )
109 {
110 // moving up ( scan top -> bottom )
111 dy1 = DestRect->top;
112 dy2 = DestRect->bottom - 1;
113 sy1 = SourcePoint->y;
114 yinc = 1;
115 }
116 else
117 {
118 // moving down ( scan bottom -> top )
119 dy1 = DestRect->bottom - 1;
120 dy2 = DestRect->top;
121 sy1 = SourcePoint->y + dy1 - dy2;
122 yinc = -1;
123 }
124 if ( DestRect->left <= SourcePoint->x )
125 {
126 // moving left ( scan left->right )
127 dwx = dl&~7;
128 swx = (sl-(dl&7))&~7;
129 dwx2 = dr&~7;
130 xinc = 1;
131 }
132 else
133 {
134 // moving right ( scan right->left )
135 dwx = dr&~7;
136 swx = (sr-(dr&7))&~7; //(sr-7)&~7; // we need the left edge of this block... thus the -7
137 dwx2 = dl&~7;
138 xinc = -1;
139 }
140 d = &(((PBYTE)DestSurf->pvScan0)[dy1*DestSurf->lDelta + (dwx>>3)]);
141 s = &(((PBYTE)SourceSurf->pvScan0)[sy1*SourceSurf->lDelta + (swx>>3)]);
142 for ( ;; )
143 {
144 dy = dy1;
145 pd = d;
146 ps = s;
147 srcmask = 0xff;
148 int dx = dwx; /* dest x for this pass */
149 if ( dwx < dl )
150 {
151 int diff = dl-dwx;
152 srcmask &= (1<<(8-diff))-1;
153 dx = dl;
154 }
155 if ( dwx+7 > dr )
156 {
157 int diff = dr-dwx+1;
158 srcmask &= ~((1<<(8-diff))-1);
159 }
160 dstmask = ~srcmask;
161
162 // we unfortunately *must* have 5 different versions of the inner
163 // loop to be certain we don't try to read from memory that is not
164 // needed and may in fact be invalid
165 if ( !shift )
166 {
167 for ( ;; )
168 {
169 *pd = (BYTE)((*pd & dstmask) | (*ps & srcmask));
170
171 // this *must* be here, because we could be going up *or* down...
172 if ( dy == dy2 )
173 break;
174 dy += yinc;
175 pd += yinc * DestSurf->lDelta;
176 ps += yinc * SourceSurf->lDelta;
177 }
178 }
179 else if ( !(0xFF00 & (srcmask<<shift) ) ) // check if ps[0] not needed...
180 {
181 for ( ;; )
182 {
183 *pd = (BYTE)((*pd & dstmask)
184 | ( ( ps[1] >> shift ) & srcmask ));
185
186 // this *must* be here, because we could be going up *or* down...
187 if ( dy == dy2 )
188 break;
189 dy += yinc;
190 pd += yinc * DestSurf->lDelta;
191 ps += yinc * SourceSurf->lDelta;
192 }
193 }
194 else if ( !(0xFF & (srcmask<<shift) ) ) // check if ps[1] not needed...
195 {
196 for ( ;; )
197 {
198 *pd = (*pd & dstmask)
199 | ( ( ps[0] << ( 8 - shift ) ) & srcmask );
200
201 // this *must* be here, because we could be going up *or* down...
202 if ( dy == dy2 )
203 break;
204 dy += yinc;
205 pd += yinc * DestSurf->lDelta;
206 ps += yinc * SourceSurf->lDelta;
207 }
208 }
209 else // both ps[0] and ps[1] are needed
210 {
211 for ( ;; )
212 {
213 *pd = (*pd & dstmask)
214 | ( ( ( (ps[1])|(ps[0]<<8) ) >> shift ) & srcmask );
215
216 // this *must* be here, because we could be going up *or* down...
217 if ( dy == dy2 )
218 break;
219 dy += yinc;
220 pd += yinc * DestSurf->lDelta;
221 ps += yinc * SourceSurf->lDelta;
222 }
223 }
224
225 // this *must* be here, because we could be going right *or* left...
226 if ( dwx == dwx2 )
227 break;
228 d += xinc;
229 s += xinc;
230 dwx += xinc<<3;
231 swx += xinc<<3;
232 }
233 }
234
235 BOOLEAN
236 DIB_1BPP_BitBltSrcCopy(
237 SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
238 SURFGDI *DestGDI, SURFGDI *SourceGDI,
239 PRECTL DestRect, POINTL *SourcePoint,
240 XLATEOBJ *ColorTranslation)
241 {
242 LONG i, j, sx, sy = SourcePoint->y;
243
244 switch ( SourceGDI->BitsPerPixel )
245 {
246 case 1:
247 DIB_1BPP_BitBltSrcCopy_From1BPP ( DestSurf, SourceSurf, DestRect, SourcePoint );
248 break;
249
250 case 4:
251 for (j=DestRect->top; j<DestRect->bottom; j++)
252 {
253 sx = SourcePoint->x;
254 for (i=DestRect->left; i<DestRect->right; i++)
255 {
256 if(XLATEOBJ_iXlate(ColorTranslation, DIB_4BPP_GetPixel(SourceSurf, sx, sy)) == 0)
257 {
258 DIB_1BPP_PutPixel(DestSurf, i, j, 0);
259 } else {
260 DIB_1BPP_PutPixel(DestSurf, i, j, 1);
261 }
262 sx++;
263 }
264 sy++;
265 }
266 break;
267
268 case 8:
269 for (j=DestRect->top; j<DestRect->bottom; j++)
270 {
271 sx = SourcePoint->x;
272 for (i=DestRect->left; i<DestRect->right; i++)
273 {
274 if(XLATEOBJ_iXlate(ColorTranslation, DIB_8BPP_GetPixel(SourceSurf, sx, sy)) == 0)
275 {
276 DIB_1BPP_PutPixel(DestSurf, i, j, 0);
277 } else {
278 DIB_1BPP_PutPixel(DestSurf, i, j, 1);
279 }
280 sx++;
281 }
282 sy++;
283 }
284 break;
285
286 case 16:
287 for (j=DestRect->top; j<DestRect->bottom; j++)
288 {
289 sx = SourcePoint->x;
290 for (i=DestRect->left; i<DestRect->right; i++)
291 {
292 if(XLATEOBJ_iXlate(ColorTranslation, DIB_16BPP_GetPixel(SourceSurf, sx, sy)) == 0)
293 {
294 DIB_1BPP_PutPixel(DestSurf, i, j, 0);
295 } else {
296 DIB_1BPP_PutPixel(DestSurf, i, j, 1);
297 }
298 sx++;
299 }
300 sy++;
301 }
302 break;
303
304 case 24:
305 for (j=DestRect->top; j<DestRect->bottom; j++)
306 {
307 sx = SourcePoint->x;
308 for (i=DestRect->left; i<DestRect->right; i++)
309 {
310 if(XLATEOBJ_iXlate(ColorTranslation, DIB_24BPP_GetPixel(SourceSurf, sx, sy)) == 0)
311 {
312 DIB_1BPP_PutPixel(DestSurf, i, j, 0);
313 } else {
314 DIB_1BPP_PutPixel(DestSurf, i, j, 1);
315 }
316 sx++;
317 }
318 sy++;
319 }
320 break;
321
322 case 32:
323 for (j=DestRect->top; j<DestRect->bottom; j++)
324 {
325 sx = SourcePoint->x;
326 for (i=DestRect->left; i<DestRect->right; i++)
327 {
328 if(XLATEOBJ_iXlate(ColorTranslation, DIB_32BPP_GetPixel(SourceSurf, sx, sy)) == 0)
329 {
330 DIB_1BPP_PutPixel(DestSurf, i, j, 0);
331 } else {
332 DIB_1BPP_PutPixel(DestSurf, i, j, 1);
333 }
334 sx++;
335 }
336 sy++;
337 }
338 break;
339
340 default:
341 DbgPrint("DIB_1BPP_BitBlt: Unhandled Source BPP: %u\n", SourceGDI->BitsPerPixel);
342 return FALSE;
343 }
344
345 return TRUE;
346 }
347
348 BOOLEAN
349 DIB_1BPP_BitBlt(
350 SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
351 SURFGDI *DestGDI, SURFGDI *SourceGDI,
352 PRECTL DestRect, POINTL *SourcePoint,
353 BRUSHOBJ *Brush, POINTL BrushOrigin,
354 XLATEOBJ *ColorTranslation, ULONG Rop4)
355 {
356 ULONG X, Y, SourceX, SourceY, k;
357 ULONG Dest, Source, Pattern = 0;
358 PULONG DestBits;
359 BOOL UsesSource;
360 BOOL UsesPattern;
361 ULONG RoundedRight;
362 BYTE NoBits;
363 /* Pattern brushes */
364 PGDIBRUSHOBJ GdiBrush;
365 HBITMAP PatternSurface = NULL;
366 SURFOBJ *PatternObj;
367 ULONG PatternWidth, PatternHeight;
368
369 if (Rop4 == SRCCOPY)
370 {
371 return DIB_1BPP_BitBltSrcCopy(
372 DestSurf,
373 SourceSurf,
374 DestGDI,
375 SourceGDI,
376 DestRect,
377 SourcePoint,
378 ColorTranslation);
379 }
380
381 UsesSource = ((Rop4 & 0xCC0000) >> 2) != (Rop4 & 0x330000);
382 UsesPattern = (((Rop4 & 0xF00000) >> 4) != (Rop4 & 0x0F0000)) && Brush;
383
384 if (UsesPattern)
385 {
386 if (Brush->iSolidColor == 0xFFFFFFFF)
387 {
388 PBITMAPOBJ PatternBitmap;
389
390 GdiBrush = CONTAINING_RECORD(
391 Brush,
392 GDIBRUSHOBJ,
393 BrushObject);
394
395 PatternBitmap = BITMAPOBJ_LockBitmap(GdiBrush->hbmPattern);
396 PatternSurface = BitmapToSurf(PatternBitmap, NULL);
397 BITMAPOBJ_UnlockBitmap(GdiBrush->hbmPattern);
398
399 PatternObj = (SURFOBJ*)AccessUserObject((ULONG)PatternSurface);
400 PatternWidth = PatternObj->sizlBitmap.cx;
401 PatternHeight = PatternObj->sizlBitmap.cy;
402
403 UsesPattern = TRUE;
404 }
405 else
406 {
407 UsesPattern = FALSE;
408 Pattern = Brush->iSolidColor;
409 }
410 }
411
412 RoundedRight = DestRect->right - ((DestRect->right - DestRect->left) & 31);
413 SourceY = SourcePoint->y;
414
415 for (Y = DestRect->top; Y < DestRect->bottom; Y++)
416 {
417 ULONG PatternY;
418
419 SourceX = SourcePoint->x;
420 DestBits = (PULONG)(
421 DestSurf->pvScan0 +
422 (DestRect->left >> 3) +
423 Y * DestSurf->lDelta);
424
425 if(UsesPattern)
426 PatternY = (Y + BrushOrigin.y) % PatternHeight;
427
428 X = DestRect->left;
429 if (X & 31)
430 {
431 /* FIXME: This case is completely untested!!! */
432
433 Dest = *((PBYTE)DestBits);
434 NoBits = 31 - (X & 31);
435
436 if (UsesSource)
437 {
438 Source = 0;
439 for (k = 31 - NoBits; k < NoBits; k++)
440 Source |= (DIB_GetSource(SourceSurf, SourceGDI, SourceX + k, SourceY, ColorTranslation) << (31 - k));
441 }
442
443 if (UsesPattern)
444 {
445 Pattern = 0;
446 for (k = 31 - NoBits; k < NoBits; k++)
447 Pattern |= (DIB_1BPP_GetPixel(PatternObj, (X + BrushOrigin.x + k) % PatternWidth, PatternY) << (31 - k));
448 }
449
450 Dest = DIB_DoRop(Rop4, Dest, Source, Pattern);
451 Dest &= ~((1 << (31 - NoBits)) - 1);
452 Dest |= *((PBYTE)DestBits) & ((1 << (31 - NoBits)) - 1);
453
454 *DestBits = Dest;
455
456 X += NoBits;
457 SourceX += NoBits;
458 }
459
460 for (; X < RoundedRight; X += 32, DestBits++, SourceX++)
461 {
462 Dest = *DestBits;
463
464 if (UsesSource)
465 {
466 Source = 0;
467 for (k = 0; k < 8; k++)
468 {
469 Source |= (DIB_GetSource(SourceSurf, SourceGDI, SourceX + k, SourceY, ColorTranslation) << (7 - k));
470 Source |= (DIB_GetSource(SourceSurf, SourceGDI, SourceX + k + 8, SourceY, ColorTranslation) << (8 + (7 - k)));
471 Source |= (DIB_GetSource(SourceSurf, SourceGDI, SourceX + k + 16, SourceY, ColorTranslation) << (16 + (7 - k)));
472 Source |= (DIB_GetSource(SourceSurf, SourceGDI, SourceX + k + 24, SourceY, ColorTranslation) << (24 + (7 - k)));
473 }
474 }
475
476 if (UsesPattern)
477 {
478 Pattern = 0;
479 for (k = 0; k < 8; k++)
480 {
481 Pattern |= (DIB_1BPP_GetPixel(PatternObj, (X + BrushOrigin.x + k) % PatternWidth, PatternY) << (7 - k));
482 Pattern |= (DIB_1BPP_GetPixel(PatternObj, (X + BrushOrigin.x + k + 8) % PatternWidth, PatternY) << (8 + (7 - k)));
483 Pattern |= (DIB_1BPP_GetPixel(PatternObj, (X + BrushOrigin.x + k + 16) % PatternWidth, PatternY) << (16 + (7 - k)));
484 Pattern |= (DIB_1BPP_GetPixel(PatternObj, (X + BrushOrigin.x + k + 24) % PatternWidth, PatternY) << (24 + (7 - k)));
485 }
486 }
487
488 *DestBits = DIB_DoRop(Rop4, Dest, Source, Pattern);
489 }
490
491 if (X < DestRect->right)
492 {
493 // Dest = *DestBits;
494 for (; X < DestRect->right; X++, SourceX++)
495 {
496 // Dest = *DestBits;
497 Dest = DIB_1BPP_GetPixel(DestSurf, X, Y);
498
499 if (UsesSource)
500 {
501 Source = DIB_GetSource(SourceSurf, SourceGDI, SourceX, SourceY, ColorTranslation);
502 }
503
504 if (UsesPattern)
505 {
506 Pattern = DIB_1BPP_GetPixel(PatternObj, (X + BrushOrigin.x) % PatternWidth, PatternY);
507 }
508
509 DIB_1BPP_PutPixel(DestSurf, X, Y, DIB_DoRop(Rop4, Dest, Source, Pattern) & 0xF);
510 // Dest >>= 1;
511 }
512 }
513
514 SourceY++;
515 }
516
517 if (PatternSurface != NULL)
518 EngDeleteSurface((HSURF)PatternSurface);
519
520 return TRUE;
521 }
522
523 BOOLEAN
524 DIB_1BPP_StretchBlt (
525 SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
526 SURFGDI *DestGDI, SURFGDI *SourceGDI,
527 RECTL* DestRect, RECTL *SourceRect,
528 POINTL* MaskOrigin, POINTL BrushOrigin,
529 XLATEOBJ *ColorTranslation, ULONG Mode)
530 {
531 DbgPrint("DIB_1BPP_StretchBlt: Source BPP: %u\n", SourceGDI->BitsPerPixel);
532 return FALSE;
533 }
534
535 BOOLEAN
536 DIB_1BPP_TransparentBlt(SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
537 PSURFGDI DestGDI, PSURFGDI SourceGDI,
538 RECTL* DestRect, POINTL *SourcePoint,
539 XLATEOBJ *ColorTranslation, ULONG iTransColor)
540 {
541 return FALSE;
542 }
543
544 /* EOF */