1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Generics backingstore operations
4 Copyright (C) Jay Sorg 2005-2006
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program 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
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "precomp.h"
22
23 /* globals */
24 static char * g_bs = 0;
25 static int g_bs_size = 0;
26
27 static int g_width1 = 800;
28 static int g_height1 = 600;
29 static int g_bpp = 8;
30 static int g_Bpp = 1;
31
32 static int g_clip_left1 = 0;
33 static int g_clip_top1 = 0;
34 static int g_clip_right1 = 800;
35 static int g_clip_bottom1 = 600;
36
37 /* for bs_patblt */
38 static char g_hatch_patterns[] =
39 {
40 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
41 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
42 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
43 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
44 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
45 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
46 };
47
48
49 /*****************************************************************************/
50 /* do a raster op */
51 int
bs_do_rop(int rop,int src,int dst)52 bs_do_rop(int rop, int src, int dst)
53 {
54 switch (rop)
55 {
56 case 0x0: return 0;
57 case 0x1: return ~(src | dst);
58 case 0x2: return (~src) & dst;
59 case 0x3: return ~src;
60 case 0x4: return src & (~dst);
61 case 0x5: return ~(dst);
62 case 0x6: return src ^ dst;
63 case 0x7: return ~(src & dst);
64 case 0x8: return src & dst;
65 case 0x9: return ~(src) ^ dst;
66 case 0xa: return dst;
67 case 0xb: return (~src) | dst;
68 case 0xc: return src;
69 case 0xd: return src | (~dst);
70 case 0xe: return src | dst;
71 case 0xf: return ~0;
72 }
73 return dst;
74 }
75
76 /*****************************************************************************/
77 /* get a pixel from the in memory copy of whats on the screen */
78 int
bs_get_pixel(int x,int y)79 bs_get_pixel(int x, int y)
80 {
81 char * p;
82
83 if (x >= 0 && x < g_width1 && y >= 0 && y < g_height1)
84 {
85 p = g_bs + (y * g_width1 * g_Bpp) + (x * g_Bpp);
86 if (g_Bpp == 1)
87 {
88 return *((unsigned char *) p);
89 }
90 else if (g_Bpp == 2)
91 {
92 return *((unsigned short *) p);
93 }
94 else
95 {
96 return *((unsigned int *) p);
97 }
98 }
99 else
100 {
101 return 0;
102 }
103 }
104
105 /*****************************************************************************/
106 /* set a pixel on the screen using the clip */
107 void
bs_set_pixel(int x,int y,int pixel,int rop,int use_clip)108 bs_set_pixel(int x, int y, int pixel, int rop, int use_clip)
109 {
110 char * p;
111
112 if (!use_clip ||
113 (x >= g_clip_left1 && x < g_clip_right1 &&
114 y >= g_clip_top1 && y < g_clip_bottom1))
115 {
116 if (x >= 0 && x < g_width1 && y >= 0 && y < g_height1)
117 {
118 p = g_bs + (y * g_width1 * g_Bpp) + (x * g_Bpp);
119 if (rop != 12)
120 {
121 pixel = bs_do_rop(rop, pixel, bs_get_pixel(x, y));
122 }
123 if (g_Bpp == 1)
124 {
125 *((unsigned char *) p) = pixel;
126 }
127 else if (g_Bpp == 2)
128 {
129 *((unsigned short *) p) = pixel;
130 }
131 else
132 {
133 *((unsigned int *) p) = pixel;
134 }
135 }
136 }
137 }
138
139 /*****************************************************************************/
140 static char *
get_bs_ptr(int x,int y)141 get_bs_ptr(int x, int y)
142 {
143 char * p;
144
145 if (x >= 0 && x < g_width1 && y >= 0 && y < g_height1)
146 {
147 p = g_bs + (y * g_width1 * g_Bpp) + (x * g_Bpp);
148 return p;
149 }
150 else
151 {
152 return 0;
153 }
154 }
155
156 /*****************************************************************************/
157 void
bs_init(int width,int height,int bpp)158 bs_init(int width, int height, int bpp)
159 {
160 if (g_bs != 0)
161 {
162 free(g_bs);
163 }
164 g_width1 = width;
165 g_height1 = height;
166 g_bpp = bpp;
167 g_Bpp = (bpp + 7) / 8;
168 g_bs_size = width * height * g_Bpp;
169 g_bs = malloc(g_bs_size);
170 memset(g_bs, 0, g_bs_size);
171 g_clip_left1 = 0;
172 g_clip_top1 = 0;
173 g_clip_right1 = width;
174 g_clip_bottom1 = height;
175 }
176
177 /*****************************************************************************/
178 void
bs_exit(void)179 bs_exit(void)
180 {
181 if (g_bs != 0)
182 {
183 free(g_bs);
184 }
185 }
186
187 /*****************************************************************************/
188 void
bs_set_clip(int x,int y,int cx,int cy)189 bs_set_clip(int x, int y, int cx, int cy)
190 {
191 g_clip_left1 = x;
192 g_clip_top1 = y;
193 g_clip_right1 = x + cx;
194 g_clip_bottom1 = y + cy;
195 }
196
197 /*****************************************************************************/
198 void
bs_reset_clip(void)199 bs_reset_clip(void)
200 {
201 g_clip_left1 = 0;
202 g_clip_top1 = 0;
203 g_clip_right1 = g_width1;
204 g_clip_bottom1 = g_height1;
205 }
206
207 /*****************************************************************************/
208 /* check if a certain pixel is set in a bitmap */
209 int
bs_is_pixel_on(char * data,int x,int y,int width,int bpp)210 bs_is_pixel_on(char * data, int x, int y, int width, int bpp)
211 {
212 int start;
213 int shift;
214
215 if (bpp == 1)
216 {
217 width = (width + 7) / 8;
218 start = (y * width) + x / 8;
219 shift = x % 8;
220 return (data[start] & (0x80 >> shift)) != 0;
221 }
222 else if (bpp == 8)
223 {
224 return data[y * width + x] != 0;
225 }
226 else if (bpp == 15 || bpp == 16)
227 {
228 return data[(y * 2) * width + (x * 2)] != 0 ||
229 data[(y * 2) * width + (x * 2) + 1] != 0;
230 }
231 else if (bpp == 24 || bpp == 32)
232 {
233 return data[(y * 4) * width + (x * 4)] != 0 ||
234 data[(y * 4) * width + (x * 4) + 1] != 0 ||
235 data[(y * 4) * width + (x * 4) + 2] != 0 ||
236 data[(y * 4) * width + (x * 4) + 3] != 0;
237 }
238 else
239 {
240 return 0;
241 }
242 }
243
244 /*****************************************************************************/
245 void
bs_set_pixel_on(char * data,int x,int y,int width,int bpp,int pixel)246 bs_set_pixel_on(char * data, int x, int y, int width, int bpp,
247 int pixel)
248 {
249 int start;
250 int shift;
251
252 if (bpp == 1)
253 {
254 width = (width + 7) / 8;
255 start = (y * width) + x / 8;
256 shift = x % 8;
257 if (pixel != 0)
258 {
259 data[start] = data[start] | (0x80 >> shift);
260 }
261 else
262 {
263 data[start] = data[start] & ~(0x80 >> shift);
264 }
265 }
266 else if (bpp == 8)
267 {
268 data[y * width + x] = pixel;
269 }
270 else if (bpp == 15 || bpp == 16)
271 {
272 ((unsigned short *) data)[y * width + x] = pixel;
273 }
274 else if (bpp == 24 || bpp == 32)
275 {
276 ((unsigned int *) data)[y * width + x] = (unsigned int) pixel;
277 }
278 }
279
280 /*****************************************************************************/
281 void
bs_copy_mem(char * d,char * s,int n)282 bs_copy_mem(char * d, char * s, int n)
283 {
284 while (n & (~7))
285 {
286 *(d++) = *(s++);
287 *(d++) = *(s++);
288 *(d++) = *(s++);
289 *(d++) = *(s++);
290 *(d++) = *(s++);
291 *(d++) = *(s++);
292 *(d++) = *(s++);
293 *(d++) = *(s++);
294 n = n - 8;
295 }
296 while (n > 0)
297 {
298 *(d++) = *(s++);
299 n--;
300 }
301 }
302
303 /*****************************************************************************/
304 void
bs_copy_memb(char * d,char * s,int n)305 bs_copy_memb(char * d, char * s, int n)
306 {
307 d = (d + n) - 1;
308 s = (s + n) - 1;
309 while (n & (~7))
310 {
311 *(d--) = *(s--);
312 *(d--) = *(s--);
313 *(d--) = *(s--);
314 *(d--) = *(s--);
315 *(d--) = *(s--);
316 *(d--) = *(s--);
317 *(d--) = *(s--);
318 *(d--) = *(s--);
319 n = n - 8;
320 }
321 while (n > 0)
322 {
323 *(d--) = *(s--);
324 n--;
325 }
326 }
327
328 /*****************************************************************************/
329 /* return true is the is something to draw */
330 int
bs_warp_coords(int * x,int * y,int * cx,int * cy,int * srcx,int * srcy)331 bs_warp_coords(int * x, int * y, int * cx, int * cy,
332 int * srcx, int * srcy)
333 {
334 int dx;
335 int dy;
336
337 if (g_clip_left1 > *x)
338 {
339 dx = g_clip_left1 - *x;
340 }
341 else
342 {
343 dx = 0;
344 }
345 if (g_clip_top1 > *y)
346 {
347 dy = g_clip_top1 - *y;
348 }
349 else
350 {
351 dy = 0;
352 }
353 if (*x + *cx > g_clip_right1)
354 {
355 *cx = (*cx - ((*x + *cx) - g_clip_right1));
356 }
357 if (*y + *cy > g_clip_bottom1)
358 {
359 *cy = (*cy - ((*y + *cy) - g_clip_bottom1));
360 }
361 *cx = *cx - dx;
362 *cy = *cy - dy;
363 if (*cx <= 0)
364 {
365 return 0;
366 }
367 if (*cy <= 0)
368 {
369 return 0;
370 }
371 *x = *x + dx;
372 *y = *y + dy;
373 if (srcx != 0)
374 {
375 *srcx = *srcx + dx;
376 }
377 if (srcy != 0)
378 {
379 *srcy = *srcy + dy;
380 }
381 return 1;
382 }
383
384 /*****************************************************************************/
385 void
bs_rect(int x,int y,int cx,int cy,int colour,int rop)386 bs_rect(int x, int y, int cx, int cy, int colour, int rop)
387 {
388 int i;
389 int j;
390 unsigned char * p8;
391 unsigned short * p16;
392 unsigned int * p32;
393
394 if (bs_warp_coords(&x, &y, &cx, &cy, 0, 0))
395 {
396 if (rop == 0) /* black */
397 {
398 rop = 12;
399 colour = 0;
400 }
401 else if (rop == 15) /* white */
402 {
403 rop = 12;
404 colour = 0xffffff;
405 }
406 if (rop == 12) /* copy */
407 {
408 if (g_Bpp == 1)
409 {
410 for (i = 0; i < cy; i++)
411 {
412 p8 = (unsigned char *) get_bs_ptr(x, y + i);
413 if (p8 != 0)
414 {
415 for (j = 0; j < cx; j++)
416 {
417 *p8 = colour;
418 p8++;
419 }
420 }
421 }
422 }
423 else if (g_Bpp == 2)
424 {
425 for (i = 0; i < cy; i++)
426 {
427 p16 = (unsigned short *) get_bs_ptr(x, y + i);
428 if (p16 != 0)
429 {
430 for (j = 0; j < cx; j++)
431 {
432 *p16 = colour;
433 p16++;
434 }
435 }
436 }
437 }
438 else
439 {
440 for (i = 0; i < cy; i++)
441 {
442 p32 = (unsigned int *) get_bs_ptr(x, y + i);
443 if (p32 != 0)
444 {
445 for (j = 0; j < cx; j++)
446 {
447 *p32 = colour;
448 p32++;
449 }
450 }
451 }
452 }
453 }
454 else /* slow */
455 {
456 for (i = 0; i < cy; i++)
457 {
458 for (j = 0; j < cx; j++)
459 {
460 bs_set_pixel(j + x, i + y, colour, rop, 0);
461 }
462 }
463 }
464 }
465 }
466
467 /*****************************************************************************/
468 void
bs_screenblt(int rop,int x,int y,int cx,int cy,int srcx,int srcy)469 bs_screenblt(int rop, int x, int y, int cx, int cy,
470 int srcx, int srcy)
471 {
472 int p;
473 int i;
474 int j;
475 char * src;
476 char * dst;
477
478 if (bs_warp_coords(&x, &y, &cx, &cy, &srcx, &srcy))
479 {
480 if (rop == 12) /* copy */
481 {
482 if (srcy < y) /* copy down - bottom to top */
483 {
484 for (i = cy - 1; i >= 0; i--)
485 {
486 src = get_bs_ptr(srcx, srcy + i);
487 dst = get_bs_ptr(x, y + i);
488 if (src != 0 && dst != 0)
489 {
490 bs_copy_mem(dst, src, cx * g_Bpp);
491 }
492 }
493 }
494 else if (srcy > y || srcx > x) /* copy up or left - top to bottom */
495 {
496 for (i = 0; i < cy; i++)
497 {
498 src = get_bs_ptr(srcx, srcy + i);
499 dst = get_bs_ptr(x, y + i);
500 if (src != 0 && dst != 0)
501 {
502 bs_copy_mem(dst, src, cx * g_Bpp);
503 }
504 }
505 }
506 else /* copy straight right */
507 {
508 for (i = 0; i < cy; i++)
509 {
510 src = get_bs_ptr(srcx, srcy + i);
511 dst = get_bs_ptr(x, y + i);
512 if (src != 0 && dst != 0)
513 {
514 bs_copy_memb(dst, src, cx * g_Bpp);
515 }
516 }
517 }
518 }
519 else /* slow */
520 {
521 if (srcy < y) /* copy down - bottom to top */
522 {
523 for (i = cy - 1; i >= 0; i--)
524 {
525 for (j = 0; j < cx; j++)
526 {
527 p = bs_get_pixel(srcx + j, srcy + i);
528 bs_set_pixel(x + j, y + i, p, rop, 0);
529 }
530 }
531 }
532 else if (srcy > y || srcx > x) /* copy up or left - top to bottom */
533 {
534 for (i = 0; i < cy; i++)
535 {
536 for (j = 0; j < cx; j++)
537 {
538 p = bs_get_pixel(srcx + j, srcy + i);
539 bs_set_pixel(x + j, y + i, p, rop, 0);
540 }
541 }
542 }
543 else /* copy straight right */
544 {
545 for (i = 0; i < cy; i++)
546 {
547 for (j = cx - 1; j >= 0; j--)
548 {
549 p = bs_get_pixel(srcx + j, srcy + i);
550 bs_set_pixel(x + j, y + i, p, rop, 0);
551 }
552 }
553 }
554 }
555 }
556 }
557
558 /*****************************************************************************/
559 void
bs_memblt(int opcode,int x,int y,int cx,int cy,void * srcdata,int srcwidth,int srcheight,int srcx,int srcy)560 bs_memblt(int opcode, int x, int y, int cx, int cy,
561 void * srcdata, int srcwidth, int srcheight,
562 int srcx, int srcy)
563 {
564 int i;
565 int j;
566 int p;
567 char * dst;
568 char * src;
569
570 if (bs_warp_coords(&x, &y, &cx, &cy, &srcx, &srcy))
571 {
572 if (opcode == 12) /* copy */
573 {
574 if (g_Bpp == 1)
575 {
576 src = (char *) (((unsigned char *) srcdata) + srcy * srcwidth + srcx);
577 }
578 else if (g_Bpp == 2)
579 {
580 src = (char *) (((unsigned short *) srcdata) + srcy * srcwidth + srcx);
581 }
582 else
583 {
584 src = (char *) (((unsigned int *) srcdata) + srcy * srcwidth + srcx);
585 }
586 for (i = 0; i < cy; i++)
587 {
588 dst = get_bs_ptr(x, y + i);
589 if (dst != 0)
590 {
591 bs_copy_mem(dst, src, cx * g_Bpp);
592 src += srcwidth * g_Bpp;
593 }
594 }
595 }
596 else /* slow */
597 {
598 if (g_Bpp == 1)
599 {
600 for (i = 0; i < cy; i++)
601 {
602 for (j = 0; j < cx; j++)
603 {
604 p = *(((unsigned char *) srcdata) +
605 ((i + srcy) * srcwidth + (j + srcx)));
606 bs_set_pixel(x + j, y + i, p, opcode, 0);
607 }
608 }
609 }
610 else if (g_Bpp == 2)
611 {
612 for (i = 0; i < cy; i++)
613 {
614 for (j = 0; j < cx; j++)
615 {
616 p = *(((unsigned short *) srcdata) +
617 ((i + srcy) * srcwidth + (j + srcx)));
618 bs_set_pixel(x + j, y + i, p, opcode, 0);
619 }
620 }
621 }
622 else
623 {
624 for (i = 0; i < cy; i++)
625 {
626 for (j = 0; j < cx; j++)
627 {
628 p = *(((unsigned int *) srcdata) +
629 ((i + srcy) * srcwidth + (j + srcx)));
630 bs_set_pixel(x + j, y + i, p, opcode, 0);
631 }
632 }
633 }
634 }
635 }
636 }
637
638 /*****************************************************************************/
639 void
bs_draw_glyph(int x,int y,char * glyph_data,int glyph_width,int glyph_height,int fgcolour)640 bs_draw_glyph(int x, int y, char * glyph_data, int glyph_width,
641 int glyph_height, int fgcolour)
642 {
643 int i;
644 int j;
645
646 for (i = 0; i < glyph_height; i++)
647 {
648 for (j = 0; j < glyph_width; j++)
649 {
650 if (bs_is_pixel_on(glyph_data, j, i, glyph_width, 8))
651 {
652 bs_set_pixel(x + j, y + i, fgcolour, 12, 1);
653 }
654 }
655 }
656 }
657
658 /*****************************************************************************/
659 /* Bresenham's line drawing algorithm */
660 void
bs_line(int opcode,int startx,int starty,int endx,int endy,int pen_width,int pen_style,int pen_colour)661 bs_line(int opcode, int startx, int starty, int endx, int endy,
662 int pen_width, int pen_style, int pen_colour)
663 {
664 int dx;
665 int dy;
666 int incx;
667 int incy;
668 int dpr;
669 int dpru;
670 int p;
671
672 if (startx > endx)
673 {
674 dx = startx - endx;
675 incx = -1;
676 }
677 else
678 {
679 dx = endx - startx;
680 incx = 1;
681 }
682 if (starty > endy)
683 {
684 dy = starty - endy;
685 incy = -1;
686 }
687 else
688 {
689 dy = endy - starty;
690 incy = 1;
691 }
692 if (dx >= dy)
693 {
694 dpr = dy << 1;
695 dpru = dpr - (dx << 1);
696 p = dpr - dx;
697 for (; dx >= 0; dx--)
698 {
699 if (startx != endx || starty != endy)
700 {
701 bs_set_pixel(startx, starty, pen_colour, opcode, 1);
702 }
703 if (p > 0)
704 {
705 startx += incx;
706 starty += incy;
707 p += dpru;
708 }
709 else
710 {
711 startx += incx;
712 p += dpr;
713 }
714 }
715 }
716 else
717 {
718 dpr = dx << 1;
719 dpru = dpr - (dy << 1);
720 p = dpr - dy;
721 for (; dy >= 0; dy--)
722 {
723 if (startx != endx || starty != endy)
724 {
725 bs_set_pixel(startx, starty, pen_colour, opcode, 1);
726 }
727 if (p > 0)
728 {
729 startx += incx;
730 starty += incy;
731 p += dpru;
732 }
733 else
734 {
735 starty += incy;
736 p += dpr;
737 }
738 }
739 }
740 }
741
742 /*****************************************************************************/
743 void
bs_patblt(int opcode,int x,int y,int cx,int cy,int brush_style,char * brush_pattern,int brush_x_org,int brush_y_org,int bgcolour,int fgcolour)744 bs_patblt(int opcode, int x, int y, int cx, int cy,
745 int brush_style, char * brush_pattern,
746 int brush_x_org, int brush_y_org,
747 int bgcolour, int fgcolour)
748 {
749 int i;
750 int j;
751 char ipattern[8];
752 char * b;
753
754 b = 0;
755 switch (brush_style)
756 {
757 case 0:
758 bs_rect(x, y, cx, cy, fgcolour, opcode);
759 break;
760 case 2: /* Hatch */
761 b = g_hatch_patterns + brush_pattern[0] * 8;
762 break;
763 case 3:
764 for (i = 0; i < 8; i++)
765 {
766 ipattern[i] = ~brush_pattern[7 - i];
767 }
768 b = ipattern;
769 break;
770 }
771 if (b != 0)
772 {
773 for (i = 0; i < cy; i++)
774 {
775 for (j = 0; j < cx; j++)
776 {
777 if (bs_is_pixel_on(b, (x + j + brush_x_org) % 8,
778 (y + i + brush_y_org) % 8, 8, 1))
779 {
780 bs_set_pixel(x + j, y + i, fgcolour, opcode, 1);
781 }
782 else
783 {
784 bs_set_pixel(x + j, y + i, bgcolour, opcode, 1);
785 }
786 }
787 }
788 }
789 }
790
791 /*****************************************************************************/
792 void
bs_copy_box(char * dst,int x,int y,int cx,int cy,int line_size)793 bs_copy_box(char * dst, int x, int y, int cx, int cy, int line_size)
794 {
795 char * src;
796 int i;
797
798 /* shouldn't happen */
799 if (cx < 1 || cy < 1)
800 {
801 return;
802 }
803 /* nothing to draw, memset and leave */
804 if (x + cx < 0 || y + cy < 0 || x >= g_width1 || y >= g_height1)
805 {
806 memset(dst, 0, cx * cy * g_Bpp);
807 return;
808 }
809 /* check if it goes over an edge */
810 if (x < 0 || y < 0 || x + cx > g_width1 || y + cy > g_height1)
811 {
812 memset(dst, 0, cx * cy * g_Bpp);
813 if (x < 0)
814 {
815 cx += x;
816 dst += -x * g_Bpp;
817 x = 0;
818 }
819 if (x + cx > g_width1)
820 {
821 cx = g_width1 - x;
822 }
823 for (i = 0; i < cy; i++)
824 {
825 src = get_bs_ptr(x, y + i);
826 if (src != 0)
827 {
828 bs_copy_mem(dst, src, cx * g_Bpp);
829 }
830 dst += line_size;
831 }
832 }
833 else /* whole box is within */
834 {
835 for (i = 0; i < cy; i++)
836 {
837 src = get_bs_ptr(x, y + i);
838 if (src != 0)
839 {
840 bs_copy_mem(dst, src, cx * g_Bpp);
841 }
842 dst += line_size;
843 }
844 }
845 }
846