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 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 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 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 * 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 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 179 bs_exit(void) 180 { 181 if (g_bs != 0) 182 { 183 free(g_bs); 184 } 185 } 186 187 /*****************************************************************************/ 188 void 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 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 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 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 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 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 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 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 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 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 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 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 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 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