summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarl Kurbjun <kkurbjun@gmail.com>2009-11-07 18:38:46 +0000
committerKarl Kurbjun <kkurbjun@gmail.com>2009-11-07 18:38:46 +0000
commit765ff0130ab58c67e82a2ed17c64c577c6434d57 (patch)
treec825c50286a468ecb421eca0cc571c1a07dfca24
parentb1783c3c64d530e77ea2301e70a000f2a624bb74 (diff)
downloadrockbox-765ff0130ab58c67e82a2ed17c64c577c6434d57.tar.gz
rockbox-765ff0130ab58c67e82a2ed17c64c577c6434d57.zip
Add optional viewport clipping, can be enabled with HAVE_VIEWPORT_CLIP. A simulator check is also added to set_viewport that will show an error/note when DEBUGF is enabled.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23551 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/drivers/lcd-16bit-vert.c283
-rw-r--r--firmware/drivers/lcd-16bit.c315
-rw-r--r--firmware/drivers/lcd-1bit-vert.c133
-rw-r--r--firmware/drivers/lcd-2bit-horz.c165
-rw-r--r--firmware/drivers/lcd-2bit-vert.c165
-rw-r--r--firmware/drivers/lcd-2bit-vi.c167
-rw-r--r--firmware/drivers/lcd-charcell.c27
-rw-r--r--firmware/export/config-mrobe500.h3
8 files changed, 1092 insertions, 166 deletions
diff --git a/firmware/drivers/lcd-16bit-vert.c b/firmware/drivers/lcd-16bit-vert.c
index 1e49bb354d..586feabeca 100644
--- a/firmware/drivers/lcd-16bit-vert.c
+++ b/firmware/drivers/lcd-16bit-vert.c
@@ -92,6 +92,28 @@ void lcd_set_viewport(struct viewport* vp)
92 current_vp = &default_vp; 92 current_vp = &default_vp;
93 else 93 else
94 current_vp = vp; 94 current_vp = vp;
95
96#if defined(SIMULATOR)
97 /* Force the viewport to be within bounds. If this happens it should
98 * be considered an error - the viewport will not draw as it might be
99 * expected.
100 */
101 if((unsigned) current_vp->x > (unsigned) LCD_WIDTH
102 || (unsigned) current_vp->y > (unsigned) LCD_HEIGHT
103 || current_vp->x + current_vp->width > LCD_WIDTH
104 || current_vp->y + current_vp->height > LCD_HEIGHT)
105 {
106#if !defined(HAVE_VIEWPORT_CLIP)
107 DEBUGF("ERROR: "
108#else
109 DEBUGF("NOTE: "
110#endif
111 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
112 current_vp->x, current_vp->y,
113 current_vp->width, current_vp->height);
114 }
115
116#endif
95} 117}
96 118
97void lcd_update_viewport(void) 119void lcd_update_viewport(void)
@@ -312,8 +334,13 @@ void lcd_clear_display(void)
312/* Set a single pixel */ 334/* Set a single pixel */
313void lcd_drawpixel(int x, int y) 335void lcd_drawpixel(int x, int y)
314{ 336{
315 if (((unsigned)x < (unsigned)current_vp->width) && 337 if ( ((unsigned)x < (unsigned)current_vp->width)
316 ((unsigned)y < (unsigned)current_vp->height)) 338 && ((unsigned)y < (unsigned)current_vp->height)
339#if defined(HAVE_VIEWPORT_CLIP)
340 && ((unsigned)x < (unsigned)LCD_WIDTH)
341 && ((unsigned)y < (unsigned)LCD_HEIGHT)
342#endif
343 )
317 lcd_fastpixelfuncs[current_vp->drawmode](LCDADDR(current_vp->x+x, current_vp->y+y)); 344 lcd_fastpixelfuncs[current_vp->drawmode](LCDADDR(current_vp->x+x, current_vp->y+y));
318} 345}
319 346
@@ -382,7 +409,13 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
382 409
383 for (i = 0; i < numpixels; i++) 410 for (i = 0; i < numpixels; i++)
384 { 411 {
385 if (((unsigned)x < (unsigned)current_vp->width) && ((unsigned)y < (unsigned)current_vp->height)) 412 if ( ((unsigned)x < (unsigned)current_vp->width)
413 && ((unsigned)y < (unsigned)current_vp->height)
414#if defined(HAVE_VIEWPORT_CLIP)
415 && ((unsigned)x < (unsigned)LCD_WIDTH)
416 && ((unsigned)y < (unsigned)LCD_HEIGHT)
417#endif
418 )
386 pfunc(LCDADDR(x + current_vp->x, y + current_vp->y)); 419 pfunc(LCDADDR(x + current_vp->x, y + current_vp->y));
387 420
388 if (d < 0) 421 if (d < 0)
@@ -415,19 +448,38 @@ void lcd_hline(int x1, int x2, int y)
415 x2 = x; 448 x2 = x;
416 } 449 }
417 450
451 /******************** In viewport clipping **********************/
418 /* nothing to draw? */ 452 /* nothing to draw? */
419 if (((unsigned)y >= (unsigned)current_vp->height) || 453 if (((unsigned)y >= (unsigned)current_vp->height) ||
420 (x1 >= current_vp->width) || 454 (x1 >= current_vp->width) ||
421 (x2 < 0)) 455 (x2 < 0))
422 return; 456 return;
423 457
424 /* clipping */
425 if (x1 < 0) 458 if (x1 < 0)
426 x1 = 0; 459 x1 = 0;
427 if (x2 >= current_vp->width) 460 if (x2 >= current_vp->width)
428 x2 = current_vp->width-1; 461 x2 = current_vp->width-1;
462
463 /* Adjust x1 and y to viewport */
464 x1 += current_vp->x;
465 x2 += current_vp->x;
466 y += current_vp->y;
467
468#if defined(HAVE_VIEWPORT_CLIP)
469 /********************* Viewport on screen clipping ********************/
470 /* nothing to draw? */
471 if (((unsigned)y >= (unsigned) LCD_HEIGHT) || (x1 >= LCD_WIDTH)
472 || (x2 < 0))
473 return;
474
475 /* clipping */
476 if (x1 < 0)
477 x1 = 0;
478 if (x2 >= LCD_WIDTH)
479 x2 = LCD_WIDTH-1;
480#endif
429 481
430 dst = LCDADDR(x1 + current_vp->x, y + current_vp->y); 482 dst = LCDADDR(x1 , y );
431 dst_end = dst + (x2 - x1) * LCD_HEIGHT; 483 dst_end = dst + (x2 - x1) * LCD_HEIGHT;
432 484
433 do 485 do
@@ -454,12 +506,39 @@ void lcd_vline(int x, int y1, int y2)
454 y2 = y; 506 y2 = y;
455 } 507 }
456 508
509 /******************** In viewport clipping **********************/
457 /* nothing to draw? */ 510 /* nothing to draw? */
458 if (((unsigned)x >= (unsigned)current_vp->width) || 511 if (((unsigned)x >= (unsigned)current_vp->width) ||
459 (y1 >= current_vp->height) || 512 (y1 >= current_vp->height) ||
460 (y2 < 0)) 513 (y2 < 0))
461 return; 514 return;
462 515
516 if (y1 < 0)
517 y1 = 0;
518 if (y2 >= current_vp->height)
519 y2 = current_vp->height-1;
520
521 /* adjust for viewport */
522 x += current_vp->x;
523 y1 += current_vp->y;
524 y2 += current_vp->y;
525
526#if defined(HAVE_VIEWPORT_CLIP)
527 /********************* Viewport on screen clipping ********************/
528 /* nothing to draw? */
529 if (( (unsigned) x >= (unsigned)LCD_WIDTH) || (y1 >= LCD_HEIGHT)
530 || (y2 < 0))
531 return;
532
533 /* clipping */
534 if (y1 < 0)
535 y1 = 0;
536 if (y2 >= LCD_HEIGHT)
537 y2 = LCD_HEIGHT-1;
538#endif
539
540 height = y2 - y1 + 1;
541
463 /* drawmode and optimisation */ 542 /* drawmode and optimisation */
464 if (current_vp->drawmode & DRMODE_INVERSEVID) 543 if (current_vp->drawmode & DRMODE_INVERSEVID)
465 { 544 {
@@ -485,18 +564,6 @@ void lcd_vline(int x, int y1, int y2)
485 if (fillopt == OPT_NONE && current_vp->drawmode != DRMODE_COMPLEMENT) 564 if (fillopt == OPT_NONE && current_vp->drawmode != DRMODE_COMPLEMENT)
486 return; 565 return;
487 566
488 /* clipping */
489 if (y1 < 0)
490 y1 = 0;
491 if (y2 >= current_vp->height)
492 y2 = current_vp->height-1;
493
494 height = y2 - y1 + 1;
495
496 /* Adjust y1 and x to viewport */
497 y1 += current_vp->y;
498 x += current_vp->x;
499
500 dst = LCDADDR(x, y1); 567 dst = LCDADDR(x, y1);
501 568
502 switch (fillopt) 569 switch (fillopt)
@@ -541,11 +608,55 @@ void lcd_fillrect(int x, int y, int width, int height)
541 enum fill_opt fillopt = OPT_NONE; 608 enum fill_opt fillopt = OPT_NONE;
542 fb_data *dst, *dst_end; 609 fb_data *dst, *dst_end;
543 610
611 /******************** In viewport clipping **********************/
544 /* nothing to draw? */ 612 /* nothing to draw? */
545 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || 613 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
546 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) 614 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
547 return; 615 return;
548 616
617 if (x < 0)
618 {
619 width += x;
620 x = 0;
621 }
622 if (y < 0)
623 {
624 height += y;
625 y = 0;
626 }
627 if (x + width > current_vp->width)
628 width = current_vp->width - x;
629 if (y + height > current_vp->height)
630 height = current_vp->height - y;
631
632 /* adjust for viewport */
633 x += current_vp->x;
634 y += current_vp->y;
635
636#if defined(HAVE_VIEWPORT_CLIP)
637 /********************* Viewport on screen clipping ********************/
638 /* nothing to draw? */
639 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
640 || (x + width <= 0) || (y + height <= 0))
641 return;
642
643 /* clip image in viewport in screen */
644 if (x < 0)
645 {
646 width += x;
647 x = 0;
648 }
649 if (y < 0)
650 {
651 height += y;
652 y = 0;
653 }
654 if (x + width > LCD_WIDTH)
655 width = LCD_WIDTH - x;
656 if (y + height > LCD_HEIGHT)
657 height = LCD_HEIGHT - y;
658#endif
659
549 /* drawmode and optimisation */ 660 /* drawmode and optimisation */
550 if (current_vp->drawmode & DRMODE_INVERSEVID) 661 if (current_vp->drawmode & DRMODE_INVERSEVID)
551 { 662 {
@@ -571,23 +682,7 @@ void lcd_fillrect(int x, int y, int width, int height)
571 if (fillopt == OPT_NONE && current_vp->drawmode != DRMODE_COMPLEMENT) 682 if (fillopt == OPT_NONE && current_vp->drawmode != DRMODE_COMPLEMENT)
572 return; 683 return;
573 684
574 /* clipping */ 685 dst = LCDADDR(x, y);
575 if (x < 0)
576 {
577 width += x;
578 x = 0;
579 }
580 if (y < 0)
581 {
582 height += y;
583 y = 0;
584 }
585 if (x + width > current_vp->width)
586 width = current_vp->width - x;
587 if (y + height > current_vp->height)
588 height = current_vp->height - y;
589
590 dst = LCDADDR(current_vp->x + x, current_vp->y + y);
591 dst_end = dst + width * LCD_HEIGHT; 686 dst_end = dst + width * LCD_HEIGHT;
592 687
593 do 688 do
@@ -641,12 +736,12 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
641 unsigned dmask = 0x100; /* bit 8 == sentinel */ 736 unsigned dmask = 0x100; /* bit 8 == sentinel */
642 int drmode = current_vp->drawmode; 737 int drmode = current_vp->drawmode;
643 738
739 /******************** Image in viewport clipping **********************/
644 /* nothing to draw? */ 740 /* nothing to draw? */
645 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || 741 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
646 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) 742 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
647 return; 743 return;
648 744
649 /* clipping */
650 if (x < 0) 745 if (x < 0)
651 { 746 {
652 width += x; 747 width += x;
@@ -663,11 +758,41 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
663 width = current_vp->width - x; 758 width = current_vp->width - x;
664 if (y + height > current_vp->height) 759 if (y + height > current_vp->height)
665 height = current_vp->height - y; 760 height = current_vp->height - y;
761
762 /* adjust for viewport */
763 x += current_vp->x;
764 y += current_vp->y;
765
766#if defined(HAVE_VIEWPORT_CLIP)
767 /********************* Viewport on screen clipping ********************/
768 /* nothing to draw? */
769 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
770 || (x + width <= 0) || (y + height <= 0))
771 return;
772
773 /* clip image in viewport in screen */
774 if (x < 0)
775 {
776 width += x;
777 src_x -= x;
778 x = 0;
779 }
780 if (y < 0)
781 {
782 height += y;
783 src_y -= y;
784 y = 0;
785 }
786 if (x + width > LCD_WIDTH)
787 width = LCD_WIDTH - x;
788 if (y + height > LCD_HEIGHT)
789 height = LCD_HEIGHT - y;
790#endif
666 791
667 src += stride * (src_y >> 3) + src_x; /* move starting point */ 792 src += stride * (src_y >> 3) + src_x; /* move starting point */
668 src_y &= 7; 793 src_y &= 7;
669 src_end = src + width; 794 src_end = src + width;
670 dst = LCDADDR(current_vp->x + x, current_vp->y + y); 795 dst = LCDADDR(x, y);
671 dst_end = dst + height; 796 dst_end = dst + height;
672 797
673 if (drmode & DRMODE_INVERSEVID) 798 if (drmode & DRMODE_INVERSEVID)
@@ -793,12 +918,12 @@ void ICODE_ATTR lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
793{ 918{
794 fb_data *dst, *dst_end; 919 fb_data *dst, *dst_end;
795 920
921 /******************** Image in viewport clipping **********************/
796 /* nothing to draw? */ 922 /* nothing to draw? */
797 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || 923 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
798 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) 924 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
799 return; 925 return;
800 926
801 /* clipping */
802 if (x < 0) 927 if (x < 0)
803 { 928 {
804 width += x; 929 width += x;
@@ -811,13 +936,44 @@ void ICODE_ATTR lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
811 src_y -= y; 936 src_y -= y;
812 y = 0; 937 y = 0;
813 } 938 }
939
814 if (x + width > current_vp->width) 940 if (x + width > current_vp->width)
815 width = current_vp->width - x; 941 width = current_vp->width - x;
816 if (y + height > current_vp->height) 942 if (y + height > current_vp->height)
817 height = current_vp->height - y; 943 height = current_vp->height - y;
944
945 /* adjust for viewport */
946 x += current_vp->x;
947 y += current_vp->y;
948
949#if defined(HAVE_VIEWPORT_CLIP)
950 /********************* Viewport on screen clipping ********************/
951 /* nothing to draw? */
952 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
953 || (x + width <= 0) || (y + height <= 0))
954 return;
955
956 /* clip image in viewport in screen */
957 if (x < 0)
958 {
959 width += x;
960 src_x -= x;
961 x = 0;
962 }
963 if (y < 0)
964 {
965 height += y;
966 src_y -= y;
967 y = 0;
968 }
969 if (x + width > LCD_WIDTH)
970 width = LCD_WIDTH - x;
971 if (y + height > LCD_HEIGHT)
972 height = LCD_HEIGHT - y;
973#endif
818 974
819 src += stride * src_x + src_y; /* move starting point */ 975 src += stride * src_x + src_y; /* move starting point */
820 dst = LCDADDR(current_vp->x + x, current_vp->y + y); 976 dst = LCDADDR(x, y);
821 dst_end = dst + width * LCD_HEIGHT; 977 dst_end = dst + width * LCD_HEIGHT;
822 978
823 do 979 do
@@ -843,13 +999,13 @@ void ICODE_ATTR lcd_bitmap_transparent_part(const fb_data *src, int src_x,
843 int y, int width, int height) 999 int y, int width, int height)
844{ 1000{
845 fb_data *dst, *dst_end; 1001 fb_data *dst, *dst_end;
846 1002
1003 /******************** Image in viewport clipping **********************/
847 /* nothing to draw? */ 1004 /* nothing to draw? */
848 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || 1005 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
849 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) 1006 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
850 return; 1007 return;
851 1008
852 /* clipping */
853 if (x < 0) 1009 if (x < 0)
854 { 1010 {
855 width += x; 1011 width += x;
@@ -862,13 +1018,44 @@ void ICODE_ATTR lcd_bitmap_transparent_part(const fb_data *src, int src_x,
862 src_y -= y; 1018 src_y -= y;
863 y = 0; 1019 y = 0;
864 } 1020 }
1021
865 if (x + width > current_vp->width) 1022 if (x + width > current_vp->width)
866 width = current_vp->width - x; 1023 width = current_vp->width - x;
867 if (y + height > current_vp->height) 1024 if (y + height > current_vp->height)
868 height = current_vp->height - y; 1025 height = current_vp->height - y;
1026
1027 /* adjust for viewport */
1028 x += current_vp->x;
1029 y += current_vp->y;
1030
1031#if defined(HAVE_VIEWPORT_CLIP)
1032 /********************* Viewport on screen clipping ********************/
1033 /* nothing to draw? */
1034 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
1035 || (x + width <= 0) || (y + height <= 0))
1036 return;
1037
1038 /* clip image in viewport in screen */
1039 if (x < 0)
1040 {
1041 width += x;
1042 src_x -= x;
1043 x = 0;
1044 }
1045 if (y < 0)
1046 {
1047 height += y;
1048 src_y -= y;
1049 y = 0;
1050 }
1051 if (x + width > LCD_WIDTH)
1052 width = LCD_WIDTH - x;
1053 if (y + height > LCD_HEIGHT)
1054 height = LCD_HEIGHT - y;
1055#endif
869 1056
870 src += stride * src_x + src_y; /* move starting point */ 1057 src += stride * src_x + src_y; /* move starting point */
871 dst = LCDADDR(current_vp->x + x, current_vp->y + y); 1058 dst = LCDADDR(x, y);
872 dst_end = dst + width * LCD_HEIGHT; 1059 dst_end = dst + width * LCD_HEIGHT;
873 1060
874 do 1061 do
diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c
index 6d6a3b2104..d8405235f7 100644
--- a/firmware/drivers/lcd-16bit.c
+++ b/firmware/drivers/lcd-16bit.c
@@ -85,6 +85,28 @@ void lcd_set_viewport(struct viewport* vp)
85 current_vp = &default_vp; 85 current_vp = &default_vp;
86 else 86 else
87 current_vp = vp; 87 current_vp = vp;
88
89#if defined(SIMULATOR)
90 /* Force the viewport to be within bounds. If this happens it should
91 * be considered an error - the viewport will not draw as it might be
92 * expected.
93 */
94 if((unsigned) current_vp->x > (unsigned) LCD_WIDTH
95 || (unsigned) current_vp->y > (unsigned) LCD_HEIGHT
96 || current_vp->x + current_vp->width > LCD_WIDTH
97 || current_vp->y + current_vp->height > LCD_HEIGHT)
98 {
99#if !defined(HAVE_VIEWPORT_CLIP)
100 DEBUGF("ERROR: "
101#else
102 DEBUGF("NOTE: "
103#endif
104 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
105 current_vp->x, current_vp->y,
106 current_vp->width, current_vp->height);
107 }
108
109#endif
88} 110}
89 111
90void lcd_update_viewport(void) 112void lcd_update_viewport(void)
@@ -305,8 +327,13 @@ void lcd_clear_display(void)
305/* Set a single pixel */ 327/* Set a single pixel */
306void lcd_drawpixel(int x, int y) 328void lcd_drawpixel(int x, int y)
307{ 329{
308 if (((unsigned)x < (unsigned)current_vp->width) && 330 if ( ((unsigned)x < (unsigned)current_vp->width)
309 ((unsigned)y < (unsigned)current_vp->height)) 331 && ((unsigned)y < (unsigned)current_vp->height)
332#if defined(HAVE_VIEWPORT_CLIP)
333 && ((unsigned)x < (unsigned)LCD_WIDTH)
334 && ((unsigned)y < (unsigned)LCD_HEIGHT)
335#endif
336 )
310 lcd_fastpixelfuncs[current_vp->drawmode](LCDADDR(current_vp->x+x, current_vp->y+y)); 337 lcd_fastpixelfuncs[current_vp->drawmode](LCDADDR(current_vp->x+x, current_vp->y+y));
311} 338}
312 339
@@ -375,7 +402,13 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
375 402
376 for (i = 0; i < numpixels; i++) 403 for (i = 0; i < numpixels; i++)
377 { 404 {
378 if (((unsigned)x < (unsigned)current_vp->width) && ((unsigned)y < (unsigned)current_vp->height)) 405 if ( ((unsigned)x < (unsigned)current_vp->width)
406 && ((unsigned)y < (unsigned)current_vp->height)
407#if defined(HAVE_VIEWPORT_CLIP)
408 && ((unsigned)x < (unsigned)LCD_WIDTH)
409 && ((unsigned)y < (unsigned)LCD_HEIGHT)
410#endif
411 )
379 pfunc(LCDADDR(x + current_vp->x, y + current_vp->y)); 412 pfunc(LCDADDR(x + current_vp->x, y + current_vp->y));
380 413
381 if (d < 0) 414 if (d < 0)
@@ -409,11 +442,38 @@ void lcd_hline(int x1, int x2, int y)
409 x2 = x; 442 x2 = x;
410 } 443 }
411 444
445 /******************** In viewport clipping **********************/
412 /* nothing to draw? */ 446 /* nothing to draw? */
413 if (((unsigned)y >= (unsigned)current_vp->height) || 447 if (((unsigned)y >= (unsigned)current_vp->height) ||
414 (x1 >= current_vp->width) || 448 (x1 >= current_vp->width) ||
415 (x2 < 0)) 449 (x2 < 0))
416 return; 450 return;
451
452 if (x1 < 0)
453 x1 = 0;
454 if (x2 >= current_vp->width)
455 x2 = current_vp->width-1;
456
457 /* Adjust x1 and y to viewport */
458 x1 += current_vp->x;
459 x2 += current_vp->x;
460 y += current_vp->y;
461
462#if defined(HAVE_VIEWPORT_CLIP)
463 /********************* Viewport on screen clipping ********************/
464 /* nothing to draw? */
465 if (((unsigned)y >= (unsigned) LCD_HEIGHT) || (x1 >= LCD_WIDTH)
466 || (x2 < 0))
467 return;
468
469 /* clipping */
470 if (x1 < 0)
471 x1 = 0;
472 if (x2 >= LCD_WIDTH)
473 x2 = LCD_WIDTH-1;
474#endif
475
476 width = x2 - x1 + 1;
417 477
418 /* drawmode and optimisation */ 478 /* drawmode and optimisation */
419 if (current_vp->drawmode & DRMODE_INVERSEVID) 479 if (current_vp->drawmode & DRMODE_INVERSEVID)
@@ -440,18 +500,6 @@ void lcd_hline(int x1, int x2, int y)
440 if (fillopt == OPT_NONE && current_vp->drawmode != DRMODE_COMPLEMENT) 500 if (fillopt == OPT_NONE && current_vp->drawmode != DRMODE_COMPLEMENT)
441 return; 501 return;
442 502
443 /* clipping */
444 if (x1 < 0)
445 x1 = 0;
446 if (x2 >= current_vp->width)
447 x2 = current_vp->width-1;
448
449 width = x2 - x1 + 1;
450
451 /* Adjust x1 and y to viewport */
452 x1 += current_vp->x;
453 y += current_vp->y;
454
455 dst = LCDADDR(x1, y); 503 dst = LCDADDR(x1, y);
456 504
457 switch (fillopt) 505 switch (fillopt)
@@ -489,19 +537,38 @@ void lcd_vline(int x, int y1, int y2)
489 y2 = y; 537 y2 = y;
490 } 538 }
491 539
540 /******************** In viewport clipping **********************/
492 /* nothing to draw? */ 541 /* nothing to draw? */
493 if (((unsigned)x >= (unsigned)current_vp->width) || 542 if (((unsigned)x >= (unsigned)current_vp->width) ||
494 (y1 >= current_vp->height) || 543 (y1 >= current_vp->height) ||
495 (y2 < 0)) 544 (y2 < 0))
496 return; 545 return;
497 546
498 /* clipping */
499 if (y1 < 0) 547 if (y1 < 0)
500 y1 = 0; 548 y1 = 0;
501 if (y2 >= current_vp->height) 549 if (y2 >= current_vp->height)
502 y2 = current_vp->height-1; 550 y2 = current_vp->height-1;
551
552 /* adjust for viewport */
553 x += current_vp->x;
554 y1 += current_vp->y;
555 y2 += current_vp->y;
556
557#if defined(HAVE_VIEWPORT_CLIP)
558 /********************* Viewport on screen clipping ********************/
559 /* nothing to draw? */
560 if (( (unsigned) x >= (unsigned)LCD_WIDTH) || (y1 >= LCD_HEIGHT)
561 || (y2 < 0))
562 return;
563
564 /* clipping */
565 if (y1 < 0)
566 y1 = 0;
567 if (y2 >= LCD_HEIGHT)
568 y2 = LCD_HEIGHT-1;
569#endif
503 570
504 dst = LCDADDR(x + current_vp->x, y1 + current_vp->y); 571 dst = LCDADDR(x , y1);
505 dst_end = dst + (y2 - y1) * LCD_WIDTH; 572 dst_end = dst + (y2 - y1) * LCD_WIDTH;
506 573
507 do 574 do
@@ -534,11 +601,55 @@ void lcd_fillrect(int x, int y, int width, int height)
534 enum fill_opt fillopt = OPT_NONE; 601 enum fill_opt fillopt = OPT_NONE;
535 fb_data *dst, *dst_end; 602 fb_data *dst, *dst_end;
536 603
604 /******************** In viewport clipping **********************/
537 /* nothing to draw? */ 605 /* nothing to draw? */
538 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || 606 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
539 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) 607 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
540 return; 608 return;
541 609
610 if (x < 0)
611 {
612 width += x;
613 x = 0;
614 }
615 if (y < 0)
616 {
617 height += y;
618 y = 0;
619 }
620 if (x + width > current_vp->width)
621 width = current_vp->width - x;
622 if (y + height > current_vp->height)
623 height = current_vp->height - y;
624
625 /* adjust for viewport */
626 x += current_vp->x;
627 y += current_vp->y;
628
629#if defined(HAVE_VIEWPORT_CLIP)
630 /********************* Viewport on screen clipping ********************/
631 /* nothing to draw? */
632 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
633 || (x + width <= 0) || (y + height <= 0))
634 return;
635
636 /* clip image in viewport in screen */
637 if (x < 0)
638 {
639 width += x;
640 x = 0;
641 }
642 if (y < 0)
643 {
644 height += y;
645 y = 0;
646 }
647 if (x + width > LCD_WIDTH)
648 width = LCD_WIDTH - x;
649 if (y + height > LCD_HEIGHT)
650 height = LCD_HEIGHT - y;
651#endif
652
542 /* drawmode and optimisation */ 653 /* drawmode and optimisation */
543 if (current_vp->drawmode & DRMODE_INVERSEVID) 654 if (current_vp->drawmode & DRMODE_INVERSEVID)
544 { 655 {
@@ -564,23 +675,7 @@ void lcd_fillrect(int x, int y, int width, int height)
564 if (fillopt == OPT_NONE && current_vp->drawmode != DRMODE_COMPLEMENT) 675 if (fillopt == OPT_NONE && current_vp->drawmode != DRMODE_COMPLEMENT)
565 return; 676 return;
566 677
567 /* clipping */ 678 dst = LCDADDR(x, y);
568 if (x < 0)
569 {
570 width += x;
571 x = 0;
572 }
573 if (y < 0)
574 {
575 height += y;
576 y = 0;
577 }
578 if (x + width > current_vp->width)
579 width = current_vp->width - x;
580 if (y + height > current_vp->height)
581 height = current_vp->height - y;
582
583 dst = LCDADDR(current_vp->x + x, current_vp->y + y);
584 dst_end = dst + height * LCD_WIDTH; 679 dst_end = dst + height * LCD_WIDTH;
585 680
586 do 681 do
@@ -634,12 +729,12 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
634 unsigned dmask = 0x100; /* bit 8 == sentinel */ 729 unsigned dmask = 0x100; /* bit 8 == sentinel */
635 int drmode = current_vp->drawmode; 730 int drmode = current_vp->drawmode;
636 731
732 /******************** Image in viewport clipping **********************/
637 /* nothing to draw? */ 733 /* nothing to draw? */
638 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || 734 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
639 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) 735 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
640 return; 736 return;
641 737
642 /* clipping */
643 if (x < 0) 738 if (x < 0)
644 { 739 {
645 width += x; 740 width += x;
@@ -656,11 +751,41 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
656 width = current_vp->width - x; 751 width = current_vp->width - x;
657 if (y + height > current_vp->height) 752 if (y + height > current_vp->height)
658 height = current_vp->height - y; 753 height = current_vp->height - y;
754
755 /* adjust for viewport */
756 x += current_vp->x;
757 y += current_vp->y;
758
759#if defined(HAVE_VIEWPORT_CLIP)
760 /********************* Viewport on screen clipping ********************/
761 /* nothing to draw? */
762 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
763 || (x + width <= 0) || (y + height <= 0))
764 return;
765
766 /* clip image in viewport in screen */
767 if (x < 0)
768 {
769 width += x;
770 src_x -= x;
771 x = 0;
772 }
773 if (y < 0)
774 {
775 height += y;
776 src_y -= y;
777 y = 0;
778 }
779 if (x + width > LCD_WIDTH)
780 width = LCD_WIDTH - x;
781 if (y + height > LCD_HEIGHT)
782 height = LCD_HEIGHT - y;
783#endif
659 784
660 src += stride * (src_y >> 3) + src_x; /* move starting point */ 785 src += stride * (src_y >> 3) + src_x; /* move starting point */
661 src_y &= 7; 786 src_y &= 7;
662 src_end = src + width; 787 src_end = src + width;
663 dst = LCDADDR(current_vp->x + x, current_vp->y + y); 788 dst = LCDADDR(x, y);
664 dst_end = dst + height * LCD_WIDTH; 789 dst_end = dst + height * LCD_WIDTH;
665 790
666 if (drmode & DRMODE_INVERSEVID) 791 if (drmode & DRMODE_INVERSEVID)
@@ -784,34 +909,62 @@ void ICODE_ATTR lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
784{ 909{
785 fb_data *dst; 910 fb_data *dst;
786 911
787 if (x + width > current_vp->width) 912 /******************** Image in viewport clipping **********************/
788 width = current_vp->width - x; /* Clip right */ 913 /* nothing to draw? */
789 914 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
790 if (x < 0) /* Clip left */ 915 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
916 return;
917
918 if (x < 0)
791 { 919 {
792 width += x; 920 width += x;
793 src_x -= x; 921 src_x -= x;
794 x = 0; 922 x = 0;
795 } 923 }
796 924 if (y < 0)
797 if (width <= 0) 925 {
798 return; /* nothing left to do */ 926 height += y;
799 927 src_y -= y;
928 y = 0;
929 }
930
931 if (x + width > current_vp->width)
932 width = current_vp->width - x;
800 if (y + height > current_vp->height) 933 if (y + height > current_vp->height)
801 height = current_vp->height - y; /* Clip bottom */ 934 height = current_vp->height - y;
802 935
803 if (y < 0) /* Clip top */ 936 /* adjust for viewport */
937 x += current_vp->x;
938 y += current_vp->y;
939
940#if defined(HAVE_VIEWPORT_CLIP)
941 /********************* Viewport on screen clipping ********************/
942 /* nothing to draw? */
943 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
944 || (x + width <= 0) || (y + height <= 0))
945 return;
946
947 /* clip image in viewport in screen */
948 if (x < 0)
949 {
950 width += x;
951 src_x -= x;
952 x = 0;
953 }
954 if (y < 0)
804 { 955 {
805 height += y; 956 height += y;
806 src_y -= y; 957 src_y -= y;
807 y = 0; 958 y = 0;
808 } 959 }
809 960 if (x + width > LCD_WIDTH)
810 if (height <= 0) 961 width = LCD_WIDTH - x;
811 return; /* nothing left to do */ 962 if (y + height > LCD_HEIGHT)
812 963 height = LCD_HEIGHT - y;
964#endif
965
813 src += stride * src_y + src_x; /* move starting point */ 966 src += stride * src_y + src_x; /* move starting point */
814 dst = LCDADDR(current_vp->x + x, current_vp->y + y); 967 dst = LCDADDR(x, y);
815 968
816 do 969 do
817 { 970 {
@@ -836,34 +989,62 @@ void ICODE_ATTR lcd_bitmap_transparent_part(const fb_data *src, int src_x,
836 fb_data *dst; 989 fb_data *dst;
837 unsigned fg = current_vp->fg_pattern; 990 unsigned fg = current_vp->fg_pattern;
838 991
839 if (x + width > current_vp->width) 992 /******************** Image in viewport clipping **********************/
840 width = current_vp->width - x; /* Clip right */ 993 /* nothing to draw? */
841 994 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
842 if (x < 0) /* Clip left */ 995 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
996 return;
997
998 if (x < 0)
843 { 999 {
844 width += x; 1000 width += x;
845 src_x -= x; 1001 src_x -= x;
846 x = 0; 1002 x = 0;
847 } 1003 }
848 1004 if (y < 0)
849 if (width <= 0) 1005 {
850 return; /* nothing left to do */ 1006 height += y;
851 1007 src_y -= y;
1008 y = 0;
1009 }
1010
1011 if (x + width > current_vp->width)
1012 width = current_vp->width - x;
852 if (y + height > current_vp->height) 1013 if (y + height > current_vp->height)
853 height = current_vp->height - y; /* Clip bottom */ 1014 height = current_vp->height - y;
854 1015
855 if (y < 0) /* Clip top */ 1016 /* adjust for viewport */
1017 x += current_vp->x;
1018 y += current_vp->y;
1019
1020#if defined(HAVE_VIEWPORT_CLIP)
1021 /********************* Viewport on screen clipping ********************/
1022 /* nothing to draw? */
1023 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
1024 || (x + width <= 0) || (y + height <= 0))
1025 return;
1026
1027 /* clip image in viewport in screen */
1028 if (x < 0)
1029 {
1030 width += x;
1031 src_x -= x;
1032 x = 0;
1033 }
1034 if (y < 0)
856 { 1035 {
857 height += y; 1036 height += y;
858 src_y -= y; 1037 src_y -= y;
859 y = 0; 1038 y = 0;
860 } 1039 }
861 1040 if (x + width > LCD_WIDTH)
862 if (height <= 0) 1041 width = LCD_WIDTH - x;
863 return; /* nothing left to do */ 1042 if (y + height > LCD_HEIGHT)
1043 height = LCD_HEIGHT - y;
1044#endif
864 1045
865 src += stride * src_y + src_x; /* move starting point */ 1046 src += stride * src_y + src_x; /* move starting point */
866 dst = LCDADDR(current_vp->x + x, current_vp->y + y); 1047 dst = LCDADDR(x, y);
867 1048
868#ifdef CPU_ARM 1049#ifdef CPU_ARM
869 { 1050 {
diff --git a/firmware/drivers/lcd-1bit-vert.c b/firmware/drivers/lcd-1bit-vert.c
index 9607f284aa..ae7cddb19a 100644
--- a/firmware/drivers/lcd-1bit-vert.c
+++ b/firmware/drivers/lcd-1bit-vert.c
@@ -66,6 +66,28 @@ void LCDFN(set_viewport)(struct viewport* vp)
66 current_vp = &default_vp; 66 current_vp = &default_vp;
67 else 67 else
68 current_vp = vp; 68 current_vp = vp;
69
70#if defined(SIMULATOR)
71 /* Force the viewport to be within bounds. If this happens it should
72 * be considered an error - the viewport will not draw as it might be
73 * expected.
74 */
75 if((unsigned) current_vp->x > (unsigned) LCDM(WIDTH)
76 || (unsigned) current_vp->y > (unsigned) LCDM(HEIGHT)
77 || current_vp->x + current_vp->width > LCDM(WIDTH)
78 || current_vp->y + current_vp->height > LCDM(HEIGHT))
79 {
80#if !defined(HAVE_VIEWPORT_CLIP)
81 DEBUGF("ERROR: "
82#else
83 DEBUGF("NOTE: "
84#endif
85 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
86 current_vp->x, current_vp->y,
87 current_vp->width, current_vp->height);
88 }
89
90#endif
69} 91}
70 92
71void LCDFN(update_viewport)(void) 93void LCDFN(update_viewport)(void)
@@ -254,8 +276,13 @@ void LCDFN(clear_viewport)(void)
254/* Set a single pixel */ 276/* Set a single pixel */
255void LCDFN(drawpixel)(int x, int y) 277void LCDFN(drawpixel)(int x, int y)
256{ 278{
257 if (((unsigned)x < (unsigned)current_vp->width) && 279 if ( ((unsigned)x < (unsigned)current_vp->width)
258 ((unsigned)y < (unsigned)current_vp->height)) 280 && ((unsigned)y < (unsigned)current_vp->height)
281#if defined(HAVE_VIEWPORT_CLIP)
282 && ((unsigned)x < (unsigned)LCDM(WIDTH))
283 && ((unsigned)y < (unsigned)LCDM(HEIGHT))
284#endif
285 )
259 LCDFN(pixelfuncs)[current_vp->drawmode](current_vp->x + x, current_vp->y + y); 286 LCDFN(pixelfuncs)[current_vp->drawmode](current_vp->x + x, current_vp->y + y);
260} 287}
261 288
@@ -324,8 +351,13 @@ void LCDFN(drawline)(int x1, int y1, int x2, int y2)
324 351
325 for (i = 0; i < numpixels; i++) 352 for (i = 0; i < numpixels; i++)
326 { 353 {
327 if (((unsigned)x < (unsigned)current_vp->width) 354 if ( ((unsigned)x < (unsigned)current_vp->width)
328 && ((unsigned)y < (unsigned)current_vp->height)) 355 && ((unsigned)y < (unsigned)current_vp->height)
356#if defined(HAVE_VIEWPORT_CLIP)
357 && ((unsigned)x < (unsigned)LCDM(WIDTH))
358 && ((unsigned)y < (unsigned)LCDM(HEIGHT))
359#endif
360 )
329 pfunc(current_vp->x + x, current_vp->y + y); 361 pfunc(current_vp->x + x, current_vp->y + y);
330 362
331 if (d < 0) 363 if (d < 0)
@@ -359,22 +391,38 @@ void LCDFN(hline)(int x1, int x2, int y)
359 x2 = x; 391 x2 = x;
360 } 392 }
361 393
394 /******************** In viewport clipping **********************/
362 /* nothing to draw? */ 395 /* nothing to draw? */
363 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width) 396 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
364 || (x2 < 0)) 397 || (x2 < 0))
365 return; 398 return;
366 399
367 /* clipping */
368 if (x1 < 0) 400 if (x1 < 0)
369 x1 = 0; 401 x1 = 0;
370 if (x2 >= current_vp->width) 402 if (x2 >= current_vp->width)
371 x2 = current_vp->width-1; 403 x2 = current_vp->width-1;
372 404
373 width = x2 - x1 + 1;
374
375 /* adjust to viewport */ 405 /* adjust to viewport */
376 x1 += current_vp->x; 406 x1 += current_vp->x;
377 y += current_vp->y; 407 y += current_vp->y;
408
409#if defined(HAVE_VIEWPORT_CLIP)
410 x2 += current_vp->x;
411
412 /********************* Viewport on screen clipping ********************/
413 /* nothing to draw? */
414 if (((unsigned)y >= (unsigned) LCDM(HEIGHT)) || (x1 >= LCDM(WIDTH))
415 || (x2 < 0))
416 return;
417
418 /* clipping */
419 if (x1 < 0)
420 x1 = 0;
421 if (x2 >= LCDM(WIDTH))
422 x2 = LCDM(WIDTH)-1;
423#endif
424
425 width = x2 - x1 + 1;
378 426
379 bfunc = LCDFN(blockfuncs)[current_vp->drawmode]; 427 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
380 dst = &LCDFN(framebuffer)[y>>3][x1]; 428 dst = &LCDFN(framebuffer)[y>>3][x1];
@@ -402,12 +450,12 @@ void LCDFN(vline)(int x, int y1, int y2)
402 y2 = ny; 450 y2 = ny;
403 } 451 }
404 452
453 /******************** In viewport clipping **********************/
405 /* nothing to draw? */ 454 /* nothing to draw? */
406 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height) 455 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
407 || (y2 < 0)) 456 || (y2 < 0))
408 return; 457 return;
409 458
410 /* clipping */
411 if (y1 < 0) 459 if (y1 < 0)
412 y1 = 0; 460 y1 = 0;
413 if (y2 >= current_vp->height) 461 if (y2 >= current_vp->height)
@@ -417,6 +465,20 @@ void LCDFN(vline)(int x, int y1, int y2)
417 y1 += current_vp->y; 465 y1 += current_vp->y;
418 y2 += current_vp->y; 466 y2 += current_vp->y;
419 x += current_vp->x; 467 x += current_vp->x;
468
469#if defined(HAVE_VIEWPORT_CLIP)
470 /********************* Viewport on screen clipping ********************/
471 /* nothing to draw? */
472 if (( (unsigned) x >= (unsigned)LCDM(WIDTH)) || (y1 >= LCDM(HEIGHT))
473 || (y2 < 0))
474 return;
475
476 /* clipping */
477 if (y1 < 0)
478 y1 = 0;
479 if (y2 >= LCDM(HEIGHT))
480 y2 = LCDM(HEIGHT)-1;
481#endif
420 482
421 bfunc = LCDFN(blockfuncs)[current_vp->drawmode]; 483 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
422 dst = &LCDFN(framebuffer)[y1>>3][x]; 484 dst = &LCDFN(framebuffer)[y1>>3][x];
@@ -459,12 +521,12 @@ void LCDFN(fillrect)(int x, int y, int width, int height)
459 LCDFN(blockfunc_type) *bfunc; 521 LCDFN(blockfunc_type) *bfunc;
460 bool fillopt = false; 522 bool fillopt = false;
461 523
524 /******************** In viewport clipping **********************/
462 /* nothing to draw? */ 525 /* nothing to draw? */
463 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) 526 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
464 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) 527 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
465 return; 528 return;
466 529
467 /* clipping */
468 if (x < 0) 530 if (x < 0)
469 { 531 {
470 width += x; 532 width += x;
@@ -483,6 +545,30 @@ void LCDFN(fillrect)(int x, int y, int width, int height)
483 /* adjust for viewport */ 545 /* adjust for viewport */
484 x += current_vp->x; 546 x += current_vp->x;
485 y += current_vp->y; 547 y += current_vp->y;
548
549#if defined(HAVE_VIEWPORT_CLIP)
550 /********************* Viewport on screen clipping ********************/
551 /* nothing to draw? */
552 if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
553 || (x + width <= 0) || (y + height <= 0))
554 return;
555
556 /* clip image in viewport in screen */
557 if (x < 0)
558 {
559 width += x;
560 x = 0;
561 }
562 if (y < 0)
563 {
564 height += y;
565 y = 0;
566 }
567 if (x + width > LCDM(WIDTH))
568 width = LCDM(WIDTH) - x;
569 if (y + height > LCDM(HEIGHT))
570 height = LCDM(HEIGHT) - y;
571#endif
486 572
487 if (current_vp->drawmode & DRMODE_INVERSEVID) 573 if (current_vp->drawmode & DRMODE_INVERSEVID)
488 { 574 {
@@ -556,12 +642,13 @@ void ICODE_ATTR LCDFN(bitmap_part)(const unsigned char *src, int src_x,
556 unsigned mask, mask_bottom; 642 unsigned mask, mask_bottom;
557 LCDFN(blockfunc_type) *bfunc; 643 LCDFN(blockfunc_type) *bfunc;
558 644
645 /******************** Image in viewport clipping **********************/
559 /* nothing to draw? */ 646 /* nothing to draw? */
560 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) 647 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
561 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) 648 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
562 return; 649 return;
563 650
564 /* clipping */ 651 /* clip image in viewport */
565 if (x < 0) 652 if (x < 0)
566 { 653 {
567 width += x; 654 width += x;
@@ -582,6 +669,32 @@ void ICODE_ATTR LCDFN(bitmap_part)(const unsigned char *src, int src_x,
582 /* adjust for viewport */ 669 /* adjust for viewport */
583 x += current_vp->x; 670 x += current_vp->x;
584 y += current_vp->y; 671 y += current_vp->y;
672
673#if defined(HAVE_VIEWPORT_CLIP)
674 /********************* Viewport on screen clipping ********************/
675 /* nothing to draw? */
676 if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
677 || (x + width <= 0) || (y + height <= 0))
678 return;
679
680 /* clip image in viewport in screen */
681 if (x < 0)
682 {
683 width += x;
684 src_x -= x;
685 x = 0;
686 }
687 if (y < 0)
688 {
689 height += y;
690 src_y -= y;
691 y = 0;
692 }
693 if (x + width > LCDM(WIDTH))
694 width = LCDM(WIDTH) - x;
695 if (y + height > LCDM(HEIGHT))
696 height = LCDM(HEIGHT) - y;
697#endif
585 698
586 src += stride * (src_y >> 3) + src_x; /* move starting point */ 699 src += stride * (src_y >> 3) + src_x; /* move starting point */
587 src_y &= 7; 700 src_y &= 7;
diff --git a/firmware/drivers/lcd-2bit-horz.c b/firmware/drivers/lcd-2bit-horz.c
index f9a53ee20c..2e965b35fa 100644
--- a/firmware/drivers/lcd-2bit-horz.c
+++ b/firmware/drivers/lcd-2bit-horz.c
@@ -87,6 +87,28 @@ void lcd_set_viewport(struct viewport* vp)
87 87
88 fg_pattern = 0x55 * (~current_vp->fg_pattern & 3); 88 fg_pattern = 0x55 * (~current_vp->fg_pattern & 3);
89 bg_pattern = 0x55 * (~current_vp->bg_pattern & 3); 89 bg_pattern = 0x55 * (~current_vp->bg_pattern & 3);
90
91#if defined(SIMULATOR)
92 /* Force the viewport to be within bounds. If this happens it should
93 * be considered an error - the viewport will not draw as it might be
94 * expected.
95 */
96 if((unsigned) current_vp->x > (unsigned) LCD_WIDTH
97 || (unsigned) current_vp->y > (unsigned) LCD_HEIGHT
98 || current_vp->x + current_vp->width > LCD_WIDTH
99 || current_vp->y + current_vp->height > LCD_HEIGHT)
100 {
101#if !defined(HAVE_VIEWPORT_CLIP)
102 DEBUGF("ERROR: "
103#else
104 DEBUGF("NOTE: "
105#endif
106 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
107 current_vp->x, current_vp->y,
108 current_vp->width, current_vp->height);
109 }
110
111#endif
90} 112}
91 113
92void lcd_update_viewport(void) 114void lcd_update_viewport(void)
@@ -415,8 +437,13 @@ void lcd_clear_viewport(void)
415/* Set a single pixel */ 437/* Set a single pixel */
416void lcd_drawpixel(int x, int y) 438void lcd_drawpixel(int x, int y)
417{ 439{
418 if (((unsigned)x < (unsigned)current_vp->width) && 440 if ( ((unsigned)x < (unsigned)current_vp->width)
419 ((unsigned)y < (unsigned)current_vp->height)) 441 && ((unsigned)y < (unsigned)current_vp->height)
442#if defined(HAVE_VIEWPORT_CLIP)
443 && ((unsigned)x < (unsigned)LCD_WIDTH)
444 && ((unsigned)y < (unsigned)LCD_HEIGHT)
445#endif
446 )
420 lcd_pixelfuncs[current_vp->drawmode](current_vp->x + x, current_vp->y + y); 447 lcd_pixelfuncs[current_vp->drawmode](current_vp->x + x, current_vp->y + y);
421} 448}
422 449
@@ -485,8 +512,13 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
485 512
486 for (i = 0; i < numpixels; i++) 513 for (i = 0; i < numpixels; i++)
487 { 514 {
488 if (((unsigned)x < (unsigned)current_vp->width) && 515 if ( ((unsigned)x < (unsigned)current_vp->width)
489 ((unsigned)y < (unsigned)current_vp->height)) 516 && ((unsigned)y < (unsigned)current_vp->height)
517#if defined(HAVE_VIEWPORT_CLIP)
518 && ((unsigned)x < (unsigned)LCD_WIDTH)
519 && ((unsigned)y < (unsigned)LCD_HEIGHT)
520#endif
521 )
490 pfunc(current_vp->x + x, current_vp->y + y); 522 pfunc(current_vp->x + x, current_vp->y + y);
491 523
492 if (d < 0) 524 if (d < 0)
@@ -520,12 +552,12 @@ void lcd_hline(int x1, int x2, int y)
520 x2 = nx; 552 x2 = nx;
521 } 553 }
522 554
555 /******************** In viewport clipping **********************/
523 /* nothing to draw? */ 556 /* nothing to draw? */
524 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width) 557 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
525 || (x2 < 0)) 558 || (x2 < 0))
526 return; 559 return;
527 560
528 /* clipping */
529 if (x1 < 0) 561 if (x1 < 0)
530 x1 = 0; 562 x1 = 0;
531 if (x2 >= current_vp->width) 563 if (x2 >= current_vp->width)
@@ -535,6 +567,20 @@ void lcd_hline(int x1, int x2, int y)
535 x1 += current_vp->x; 567 x1 += current_vp->x;
536 x2 += current_vp->x; 568 x2 += current_vp->x;
537 y += current_vp->y; 569 y += current_vp->y;
570
571#if defined(HAVE_VIEWPORT_CLIP)
572 /********************* Viewport on screen clipping ********************/
573 /* nothing to draw? */
574 if (((unsigned)y >= (unsigned) LCD_HEIGHT) || (x1 >= LCD_WIDTH)
575 || (x2 < 0))
576 return;
577
578 /* clipping */
579 if (x1 < 0)
580 x1 = 0;
581 if (x2 >= LCD_WIDTH)
582 x2 = LCD_WIDTH-1;
583#endif
538 584
539 bfunc = lcd_blockfuncs[current_vp->drawmode]; 585 bfunc = lcd_blockfuncs[current_vp->drawmode];
540 dst = &lcd_framebuffer[y][x1>>2]; 586 dst = &lcd_framebuffer[y][x1>>2];
@@ -567,12 +613,12 @@ void lcd_vline(int x, int y1, int y2)
567 y2 = y; 613 y2 = y;
568 } 614 }
569 615
616 /******************** In viewport clipping **********************/
570 /* nothing to draw? */ 617 /* nothing to draw? */
571 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height) 618 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
572 || (y2 < 0)) 619 || (y2 < 0))
573 return; 620 return;
574 621
575 /* clipping */
576 if (y1 < 0) 622 if (y1 < 0)
577 y1 = 0; 623 y1 = 0;
578 if (y2 >= current_vp->height) 624 if (y2 >= current_vp->height)
@@ -582,6 +628,20 @@ void lcd_vline(int x, int y1, int y2)
582 y1 += current_vp->y; 628 y1 += current_vp->y;
583 y2 += current_vp->y; 629 y2 += current_vp->y;
584 x += current_vp->x; 630 x += current_vp->x;
631
632#if defined(HAVE_VIEWPORT_CLIP)
633 /********************* Viewport on screen clipping ********************/
634 /* nothing to draw? */
635 if (( (unsigned) x >= (unsigned)LCD_WIDTH) || (y1 >= LCD_HEIGHT)
636 || (y2 < 0))
637 return;
638
639 /* clipping */
640 if (y1 < 0)
641 y1 = 0;
642 if (y2 >= LCD_HEIGHT)
643 y2 = LCD_HEIGHT-1;
644#endif
585 645
586 bfunc = lcd_blockfuncs[current_vp->drawmode]; 646 bfunc = lcd_blockfuncs[current_vp->drawmode];
587 dst = &lcd_framebuffer[y1][x>>2]; 647 dst = &lcd_framebuffer[y1][x>>2];
@@ -619,12 +679,12 @@ void lcd_fillrect(int x, int y, int width, int height)
619 unsigned mask, mask_right; 679 unsigned mask, mask_right;
620 lcd_blockfunc_type *bfunc; 680 lcd_blockfunc_type *bfunc;
621 681
682 /******************** In viewport clipping **********************/
622 /* nothing to draw? */ 683 /* nothing to draw? */
623 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || (y >= current_vp->height) 684 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || (y >= current_vp->height)
624 || (x + width <= 0) || (y + height <= 0)) 685 || (x + width <= 0) || (y + height <= 0))
625 return; 686 return;
626 687
627 /* clipping */
628 if (x < 0) 688 if (x < 0)
629 { 689 {
630 width += x; 690 width += x;
@@ -643,6 +703,30 @@ void lcd_fillrect(int x, int y, int width, int height)
643 /* adjust for viewport */ 703 /* adjust for viewport */
644 x += current_vp->x; 704 x += current_vp->x;
645 y += current_vp->y; 705 y += current_vp->y;
706
707#if defined(HAVE_VIEWPORT_CLIP)
708 /********************* Viewport on screen clipping ********************/
709 /* nothing to draw? */
710 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
711 || (x + width <= 0) || (y + height <= 0))
712 return;
713
714 /* clip image in viewport in screen */
715 if (x < 0)
716 {
717 width += x;
718 x = 0;
719 }
720 if (y < 0)
721 {
722 height += y;
723 y = 0;
724 }
725 if (x + width > LCD_WIDTH)
726 width = LCD_WIDTH - x;
727 if (y + height > LCD_HEIGHT)
728 height = LCD_HEIGHT - y;
729#endif
646 730
647 bfunc = lcd_blockfuncs[current_vp->drawmode]; 731 bfunc = lcd_blockfuncs[current_vp->drawmode];
648 dst = &lcd_framebuffer[y][x>>2]; 732 dst = &lcd_framebuffer[y][x>>2];
@@ -696,12 +780,12 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
696 unsigned dst_mask; 780 unsigned dst_mask;
697 int drmode = current_vp->drawmode; 781 int drmode = current_vp->drawmode;
698 782
783 /******************** Image in viewport clipping **********************/
699 /* nothing to draw? */ 784 /* nothing to draw? */
700 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || 785 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
701 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) 786 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
702 return; 787 return;
703 788
704 /* clipping */
705 if (x < 0) 789 if (x < 0)
706 { 790 {
707 width += x; 791 width += x;
@@ -718,12 +802,41 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
718 width = current_vp->width - x; 802 width = current_vp->width - x;
719 if (y + height > current_vp->height) 803 if (y + height > current_vp->height)
720 height = current_vp->height - y; 804 height = current_vp->height - y;
805
806 x += current_vp->x; /* adjust for viewport */
807 y += current_vp->y; /* adjust for viewport */
808
809#if defined(HAVE_VIEWPORT_CLIP)
810 /********************* Viewport on screen clipping ********************/
811 /* nothing to draw? */
812 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
813 || (x + width <= 0) || (y + height <= 0))
814 return;
815
816 /* clip image in viewport in screen */
817 if (x < 0)
818 {
819 width += x;
820 src_x -= x;
821 x = 0;
822 }
823 if (y < 0)
824 {
825 height += y;
826 src_y -= y;
827 y = 0;
828 }
829 if (x + width > LCD_WIDTH)
830 width = LCD_WIDTH - x;
831 if (y + height > LCD_HEIGHT)
832 height = LCD_HEIGHT - y;
833#endif
721 834
722 src += stride * (src_y >> 3) + src_x; /* move starting point */ 835 src += stride * (src_y >> 3) + src_x; /* move starting point */
723 src_y &= 7; 836 src_y &= 7;
724 src_end = src + width; 837 src_end = src + width;
725 x += current_vp->x; /* adjust for viewport */ 838
726 dst = &lcd_framebuffer[current_vp->y + y][x >> 2]; 839 dst = &lcd_framebuffer[y][x >> 2];
727 dst_end = dst + height * LCD_FBWIDTH; 840 dst_end = dst + height * LCD_FBWIDTH;
728 dst_mask = pixmask[x & 3]; 841 dst_mask = pixmask[x & 3];
729 842
@@ -879,12 +992,12 @@ void ICODE_ATTR lcd_bitmap_part(const unsigned char *src, int src_x,
879 unsigned char *dst, *dst_end; 992 unsigned char *dst, *dst_end;
880 unsigned mask, mask_right; 993 unsigned mask, mask_right;
881 994
995 /******************** Image in viewport clipping **********************/
882 /* nothing to draw? */ 996 /* nothing to draw? */
883 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || 997 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
884 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) 998 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
885 return; 999 return;
886 1000
887 /* clipping */
888 if (x < 0) 1001 if (x < 0)
889 { 1002 {
890 width += x; 1003 width += x;
@@ -905,6 +1018,32 @@ void ICODE_ATTR lcd_bitmap_part(const unsigned char *src, int src_x,
905 /* adjust for viewport */ 1018 /* adjust for viewport */
906 x += current_vp->x; 1019 x += current_vp->x;
907 y += current_vp->y; 1020 y += current_vp->y;
1021
1022#if defined(HAVE_VIEWPORT_CLIP)
1023 /********************* Viewport on screen clipping ********************/
1024 /* nothing to draw? */
1025 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
1026 || (x + width <= 0) || (y + height <= 0))
1027 return;
1028
1029 /* clip image in viewport in screen */
1030 if (x < 0)
1031 {
1032 width += x;
1033 src_x -= x;
1034 x = 0;
1035 }
1036 if (y < 0)
1037 {
1038 height += y;
1039 src_y -= y;
1040 y = 0;
1041 }
1042 if (x + width > LCD_WIDTH)
1043 width = LCD_WIDTH - x;
1044 if (y + height > LCD_HEIGHT)
1045 height = LCD_HEIGHT - y;
1046#endif
908 1047
909 stride = (stride + 3) >> 2; /* convert to no. of bytes */ 1048 stride = (stride + 3) >> 2; /* convert to no. of bytes */
910 1049
diff --git a/firmware/drivers/lcd-2bit-vert.c b/firmware/drivers/lcd-2bit-vert.c
index a124e3e15d..3a089722f4 100644
--- a/firmware/drivers/lcd-2bit-vert.c
+++ b/firmware/drivers/lcd-2bit-vert.c
@@ -89,6 +89,28 @@ void lcd_set_viewport(struct viewport* vp)
89 89
90 fg_pattern = 0x55 * (~current_vp->fg_pattern & 3); 90 fg_pattern = 0x55 * (~current_vp->fg_pattern & 3);
91 bg_pattern = 0x55 * (~current_vp->bg_pattern & 3); 91 bg_pattern = 0x55 * (~current_vp->bg_pattern & 3);
92
93#if defined(SIMULATOR)
94 /* Force the viewport to be within bounds. If this happens it should
95 * be considered an error - the viewport will not draw as it might be
96 * expected.
97 */
98 if((unsigned) current_vp->x > (unsigned) LCD_WIDTH
99 || (unsigned) current_vp->y > (unsigned) LCD_HEIGHT
100 || current_vp->x + current_vp->width > LCD_WIDTH
101 || current_vp->y + current_vp->height > LCD_HEIGHT)
102 {
103#if !defined(HAVE_VIEWPORT_CLIP)
104 DEBUGF("ERROR: "
105#else
106 DEBUGF("NOTE: "
107#endif
108 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
109 current_vp->x, current_vp->y,
110 current_vp->width, current_vp->height);
111 }
112
113#endif
92} 114}
93 115
94void lcd_update_viewport(void) 116void lcd_update_viewport(void)
@@ -418,8 +440,13 @@ void lcd_clear_viewport(void)
418/* Set a single pixel */ 440/* Set a single pixel */
419void lcd_drawpixel(int x, int y) 441void lcd_drawpixel(int x, int y)
420{ 442{
421 if (((unsigned)x < (unsigned)current_vp->width) && 443 if ( ((unsigned)x < (unsigned)current_vp->width)
422 ((unsigned)y < (unsigned)current_vp->height)) 444 && ((unsigned)y < (unsigned)current_vp->height)
445#if defined(HAVE_VIEWPORT_CLIP)
446 && ((unsigned)x < (unsigned)LCD_WIDTH)
447 && ((unsigned)y < (unsigned)LCD_HEIGHT)
448#endif
449 )
423 lcd_pixelfuncs[current_vp->drawmode](current_vp->x + x, current_vp->y + y); 450 lcd_pixelfuncs[current_vp->drawmode](current_vp->x + x, current_vp->y + y);
424} 451}
425 452
@@ -488,8 +515,13 @@ void lcd_drawline(int x1, int y1, int x2, int y2)
488 515
489 for (i = 0; i < numpixels; i++) 516 for (i = 0; i < numpixels; i++)
490 { 517 {
491 if (((unsigned)x < (unsigned)current_vp->width) && 518 if ( ((unsigned)x < (unsigned)current_vp->width)
492 ((unsigned)y < (unsigned)current_vp->height)) 519 && ((unsigned)y < (unsigned)current_vp->height)
520#if defined(HAVE_VIEWPORT_CLIP)
521 && ((unsigned)x < (unsigned)LCD_WIDTH)
522 && ((unsigned)y < (unsigned)LCD_HEIGHT)
523#endif
524 )
493 pfunc(current_vp->x + x, current_vp->y + y); 525 pfunc(current_vp->x + x, current_vp->y + y);
494 526
495 if (d < 0) 527 if (d < 0)
@@ -524,22 +556,37 @@ void lcd_hline(int x1, int x2, int y)
524 x2 = x; 556 x2 = x;
525 } 557 }
526 558
559 /******************** In viewport clipping **********************/
527 /* nothing to draw? */ 560 /* nothing to draw? */
528 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width) 561 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
529 || (x2 < 0)) 562 || (x2 < 0))
530 return; 563 return;
531 564
532 /* clipping */
533 if (x1 < 0) 565 if (x1 < 0)
534 x1 = 0; 566 x1 = 0;
535 if (x2 >= current_vp->width) 567 if (x2 >= current_vp->width)
536 x2 = current_vp->width-1; 568 x2 = current_vp->width-1;
537 569
538 width = x2 - x1 + 1;
539
540 /* adjust x1 and y to viewport */ 570 /* adjust x1 and y to viewport */
541 x1 += current_vp->x; 571 x1 += current_vp->x;
572 x2 += current_vp->x;
542 y += current_vp->y; 573 y += current_vp->y;
574
575#if defined(HAVE_VIEWPORT_CLIP)
576 /********************* Viewport on screen clipping ********************/
577 /* nothing to draw? */
578 if (((unsigned)y >= (unsigned) LCD_HEIGHT) || (x1 >= LCD_WIDTH)
579 || (x2 < 0))
580 return;
581
582 /* clipping */
583 if (x1 < 0)
584 x1 = 0;
585 if (x2 >= LCD_WIDTH)
586 x2 = LCD_WIDTH-1;
587#endif
588
589 width = x2 - x1 + 1;
543 590
544 bfunc = lcd_blockfuncs[current_vp->drawmode]; 591 bfunc = lcd_blockfuncs[current_vp->drawmode];
545 dst = &lcd_framebuffer[y>>2][x1]; 592 dst = &lcd_framebuffer[y>>2][x1];
@@ -567,12 +614,12 @@ void lcd_vline(int x, int y1, int y2)
567 y2 = ny; 614 y2 = ny;
568 } 615 }
569 616
617 /******************** In viewport clipping **********************/
570 /* nothing to draw? */ 618 /* nothing to draw? */
571 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height) 619 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
572 || (y2 < 0)) 620 || (y2 < 0))
573 return; 621 return;
574 622
575 /* clipping */
576 if (y1 < 0) 623 if (y1 < 0)
577 y1 = 0; 624 y1 = 0;
578 if (y2 >= current_vp->height) 625 if (y2 >= current_vp->height)
@@ -582,6 +629,20 @@ void lcd_vline(int x, int y1, int y2)
582 y1 += current_vp->y; 629 y1 += current_vp->y;
583 y2 += current_vp->y; 630 y2 += current_vp->y;
584 x += current_vp->x; 631 x += current_vp->x;
632
633#if defined(HAVE_VIEWPORT_CLIP)
634 /********************* Viewport on screen clipping ********************/
635 /* nothing to draw? */
636 if (( (unsigned) x >= (unsigned)LCD_WIDTH) || (y1 >= LCD_HEIGHT)
637 || (y2 < 0))
638 return;
639
640 /* clipping */
641 if (y1 < 0)
642 y1 = 0;
643 if (y2 >= LCD_HEIGHT)
644 y2 = LCD_HEIGHT-1;
645#endif
585 646
586 bfunc = lcd_blockfuncs[current_vp->drawmode]; 647 bfunc = lcd_blockfuncs[current_vp->drawmode];
587 dst = &lcd_framebuffer[y1>>2][x]; 648 dst = &lcd_framebuffer[y1>>2][x];
@@ -624,12 +685,12 @@ void lcd_fillrect(int x, int y, int width, int height)
624 lcd_blockfunc_type *bfunc; 685 lcd_blockfunc_type *bfunc;
625 bool fillopt = false; 686 bool fillopt = false;
626 687
688 /******************** In viewport clipping **********************/
627 /* nothing to draw? */ 689 /* nothing to draw? */
628 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) 690 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
629 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) 691 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
630 return; 692 return;
631 693
632 /* clipping */
633 if (x < 0) 694 if (x < 0)
634 { 695 {
635 width += x; 696 width += x;
@@ -648,6 +709,30 @@ void lcd_fillrect(int x, int y, int width, int height)
648 /* adjust for viewport */ 709 /* adjust for viewport */
649 x += current_vp->x; 710 x += current_vp->x;
650 y += current_vp->y; 711 y += current_vp->y;
712
713#if defined(HAVE_VIEWPORT_CLIP)
714 /********************* Viewport on screen clipping ********************/
715 /* nothing to draw? */
716 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
717 || (x + width <= 0) || (y + height <= 0))
718 return;
719
720 /* clip image in viewport in screen */
721 if (x < 0)
722 {
723 width += x;
724 x = 0;
725 }
726 if (y < 0)
727 {
728 height += y;
729 y = 0;
730 }
731 if (x + width > LCD_WIDTH)
732 width = LCD_WIDTH - x;
733 if (y + height > LCD_HEIGHT)
734 height = LCD_HEIGHT - y;
735#endif
651 736
652 if (current_vp->drawmode & DRMODE_INVERSEVID) 737 if (current_vp->drawmode & DRMODE_INVERSEVID)
653 { 738 {
@@ -722,12 +807,12 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
722 unsigned mask, mask_bottom; 807 unsigned mask, mask_bottom;
723 lcd_blockfunc_type *bfunc; 808 lcd_blockfunc_type *bfunc;
724 809
810 /******************** Image in viewport clipping **********************/
725 /* nothing to draw? */ 811 /* nothing to draw? */
726 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || 812 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
727 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) 813 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
728 return; 814 return;
729 815
730 /* clipping */
731 if (x < 0) 816 if (x < 0)
732 { 817 {
733 width += x; 818 width += x;
@@ -748,6 +833,32 @@ void ICODE_ATTR lcd_mono_bitmap_part(const unsigned char *src, int src_x,
748 /* adjust for viewport */ 833 /* adjust for viewport */
749 x += current_vp->x; 834 x += current_vp->x;
750 y += current_vp->y; 835 y += current_vp->y;
836
837#if defined(HAVE_VIEWPORT_CLIP)
838 /********************* Viewport on screen clipping ********************/
839 /* nothing to draw? */
840 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
841 || (x + width <= 0) || (y + height <= 0))
842 return;
843
844 /* clip image in viewport in screen */
845 if (x < 0)
846 {
847 width += x;
848 src_x -= x;
849 x = 0;
850 }
851 if (y < 0)
852 {
853 height += y;
854 src_y -= y;
855 y = 0;
856 }
857 if (x + width > LCD_WIDTH)
858 width = LCD_WIDTH - x;
859 if (y + height > LCD_HEIGHT)
860 height = LCD_HEIGHT - y;
861#endif
751 862
752 src += stride * (src_y >> 3) + src_x; /* move starting point */ 863 src += stride * (src_y >> 3) + src_x; /* move starting point */
753 src_y &= 7; 864 src_y &= 7;
@@ -893,12 +1004,12 @@ void ICODE_ATTR lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
893 fb_data *dst, *dst_end; 1004 fb_data *dst, *dst_end;
894 unsigned mask, mask_bottom; 1005 unsigned mask, mask_bottom;
895 1006
1007 /******************** Image in viewport clipping **********************/
896 /* nothing to draw? */ 1008 /* nothing to draw? */
897 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) 1009 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
898 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) 1010 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
899 return; 1011 return;
900 1012
901 /* clipping */
902 if (x < 0) 1013 if (x < 0)
903 { 1014 {
904 width += x; 1015 width += x;
@@ -919,6 +1030,32 @@ void ICODE_ATTR lcd_bitmap_part(const fb_data *src, int src_x, int src_y,
919 /* adjust for viewport */ 1030 /* adjust for viewport */
920 x += current_vp->x; 1031 x += current_vp->x;
921 y += current_vp->y; 1032 y += current_vp->y;
1033
1034#if defined(HAVE_VIEWPORT_CLIP)
1035 /********************* Viewport on screen clipping ********************/
1036 /* nothing to draw? */
1037 if ((x >= LCD_WIDTH) || (y >= LCD_HEIGHT)
1038 || (x + width <= 0) || (y + height <= 0))
1039 return;
1040
1041 /* clip image in viewport in screen */
1042 if (x < 0)
1043 {
1044 width += x;
1045 src_x -= x;
1046 x = 0;
1047 }
1048 if (y < 0)
1049 {
1050 height += y;
1051 src_y -= y;
1052 y = 0;
1053 }
1054 if (x + width > LCD_WIDTH)
1055 width = LCD_WIDTH - x;
1056 if (y + height > LCD_HEIGHT)
1057 height = LCD_HEIGHT - y;
1058#endif
922 1059
923 src += stride * (src_y >> 2) + src_x; /* move starting point */ 1060 src += stride * (src_y >> 2) + src_x; /* move starting point */
924 src_y &= 3; 1061 src_y &= 3;
diff --git a/firmware/drivers/lcd-2bit-vi.c b/firmware/drivers/lcd-2bit-vi.c
index 9ce952b9e0..5edb588ce0 100644
--- a/firmware/drivers/lcd-2bit-vi.c
+++ b/firmware/drivers/lcd-2bit-vi.c
@@ -82,6 +82,28 @@ void LCDFN(set_viewport)(struct viewport* vp)
82 82
83 fg_pattern = patterns[current_vp->fg_pattern & 3]; 83 fg_pattern = patterns[current_vp->fg_pattern & 3];
84 bg_pattern = patterns[current_vp->bg_pattern & 3]; 84 bg_pattern = patterns[current_vp->bg_pattern & 3];
85
86#if defined(SIMULATOR)
87 /* Force the viewport to be within bounds. If this happens it should
88 * be considered an error - the viewport will not draw as it might be
89 * expected.
90 */
91 if((unsigned) current_vp->x > (unsigned) LCDM(WIDTH)
92 || (unsigned) current_vp->y > (unsigned) LCDM(HEIGHT)
93 || current_vp->x + current_vp->width > LCDM(WIDTH)
94 || current_vp->y + current_vp->height > LCDM(HEIGHT))
95 {
96#if !defined(HAVE_VIEWPORT_CLIP)
97 DEBUGF("ERROR: "
98#else
99 DEBUGF("NOTE: "
100#endif
101 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
102 current_vp->x, current_vp->y,
103 current_vp->width, current_vp->height);
104 }
105
106#endif
85} 107}
86 108
87void LCDFN(update_viewport)(void) 109void LCDFN(update_viewport)(void)
@@ -443,8 +465,13 @@ void LCDFN(clear_viewport)(void)
443/* Set a single pixel */ 465/* Set a single pixel */
444void LCDFN(drawpixel)(int x, int y) 466void LCDFN(drawpixel)(int x, int y)
445{ 467{
446 if (((unsigned)x < (unsigned)current_vp->width) && 468 if ( ((unsigned)x < (unsigned)current_vp->width)
447 ((unsigned)y < (unsigned)current_vp->height)) 469 && ((unsigned)y < (unsigned)current_vp->height)
470#if defined(HAVE_VIEWPORT_CLIP)
471 && ((unsigned)x < (unsigned)LCDM(WIDTH))
472 && ((unsigned)y < (unsigned)LCDM(HEIGHT))
473#endif
474 )
448 LCDFN(pixelfuncs)[current_vp->drawmode](current_vp->x+x, current_vp->y+y); 475 LCDFN(pixelfuncs)[current_vp->drawmode](current_vp->x+x, current_vp->y+y);
449} 476}
450 477
@@ -513,8 +540,13 @@ void LCDFN(drawline)(int x1, int y1, int x2, int y2)
513 540
514 for (i = 0; i < numpixels; i++) 541 for (i = 0; i < numpixels; i++)
515 { 542 {
516 if (((unsigned)x < (unsigned)current_vp->width) && 543 if ( ((unsigned)x < (unsigned)current_vp->width)
517 ((unsigned)y < (unsigned)current_vp->height)) 544 && ((unsigned)y < (unsigned)current_vp->height)
545#if defined(HAVE_VIEWPORT_CLIP)
546 && ((unsigned)x < (unsigned)LCDM(WIDTH))
547 && ((unsigned)y < (unsigned)LCDM(HEIGHT))
548#endif
549 )
518 pfunc(current_vp->x + x, current_vp->y + y); 550 pfunc(current_vp->x + x, current_vp->y + y);
519 551
520 if (d < 0) 552 if (d < 0)
@@ -548,24 +580,40 @@ void LCDFN(hline)(int x1, int x2, int y)
548 x1 = x2; 580 x1 = x2;
549 x2 = x; 581 x2 = x;
550 } 582 }
551 583
584 /******************** In viewport clipping **********************/
552 /* nothing to draw? */ 585 /* nothing to draw? */
553 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width) 586 if (((unsigned)y >= (unsigned)current_vp->height) || (x1 >= current_vp->width)
554 || (x2 < 0)) 587 || (x2 < 0))
555 return; 588 return;
556 589
557 /* clipping */
558 if (x1 < 0) 590 if (x1 < 0)
559 x1 = 0; 591 x1 = 0;
560 if (x2 >= current_vp->width) 592 if (x2 >= current_vp->width)
561 x2 = current_vp->width-1; 593 x2 = current_vp->width-1;
562 594
563 width = x2 - x1 + 1;
564
565 /* adjust x1 and y to viewport */ 595 /* adjust x1 and y to viewport */
566 x1 += current_vp->x; 596 x1 += current_vp->x;
567 y += current_vp->y; 597 y += current_vp->y;
568 598
599#if defined(HAVE_VIEWPORT_CLIP)
600 x2 += current_vp->x;
601
602 /********************* Viewport on screen clipping ********************/
603 /* nothing to draw? */
604 if (((unsigned)y >= (unsigned) LCDM(HEIGHT)) || (x1 >= LCDM(WIDTH))
605 || (x2 < 0))
606 return;
607
608 /* clipping */
609 if (x1 < 0)
610 x1 = 0;
611 if (x2 >= LCDM(WIDTH))
612 x2 = LCDM(WIDTH)-1;
613#endif
614
615 width = x2 - x1 + 1;
616
569 bfunc = LCDFN(blockfuncs)[current_vp->drawmode]; 617 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
570 dst = &LCDFN(framebuffer)[y>>3][x1]; 618 dst = &LCDFN(framebuffer)[y>>3][x1];
571 mask = 0x0101 << (y & 7); 619 mask = 0x0101 << (y & 7);
@@ -592,12 +640,12 @@ void LCDFN(vline)(int x, int y1, int y2)
592 y2 = ny; 640 y2 = ny;
593 } 641 }
594 642
643 /******************** In viewport clipping **********************/
595 /* nothing to draw? */ 644 /* nothing to draw? */
596 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height) 645 if (((unsigned)x >= (unsigned)current_vp->width) || (y1 >= current_vp->height)
597 || (y2 < 0)) 646 || (y2 < 0))
598 return; 647 return;
599 648
600 /* clipping */
601 if (y1 < 0) 649 if (y1 < 0)
602 y1 = 0; 650 y1 = 0;
603 if (y2 >= current_vp->height) 651 if (y2 >= current_vp->height)
@@ -607,6 +655,20 @@ void LCDFN(vline)(int x, int y1, int y2)
607 y1 += current_vp->y; 655 y1 += current_vp->y;
608 y2 += current_vp->y; 656 y2 += current_vp->y;
609 x += current_vp->x; 657 x += current_vp->x;
658
659#if defined(HAVE_VIEWPORT_CLIP)
660 /********************* Viewport on screen clipping ********************/
661 /* nothing to draw? */
662 if (( (unsigned) x >= (unsigned)LCDM(WIDTH)) || (y1 >= LCDM(HEIGHT))
663 || (y2 < 0))
664 return;
665
666 /* clipping */
667 if (y1 < 0)
668 y1 = 0;
669 if (y2 >= LCDM(HEIGHT))
670 y2 = LCDM(HEIGHT)-1;
671#endif
610 672
611 bfunc = LCDFN(blockfuncs)[current_vp->drawmode]; 673 bfunc = LCDFN(blockfuncs)[current_vp->drawmode];
612 dst = &LCDFN(framebuffer)[y1>>3][x]; 674 dst = &LCDFN(framebuffer)[y1>>3][x];
@@ -651,12 +713,12 @@ void LCDFN(fillrect)(int x, int y, int width, int height)
651 LCDFN(blockfunc_type) *bfunc; 713 LCDFN(blockfunc_type) *bfunc;
652 bool fillopt = false; 714 bool fillopt = false;
653 715
716 /******************** In viewport clipping **********************/
654 /* nothing to draw? */ 717 /* nothing to draw? */
655 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) 718 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
656 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) 719 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
657 return; 720 return;
658 721
659 /* clipping */
660 if (x < 0) 722 if (x < 0)
661 { 723 {
662 width += x; 724 width += x;
@@ -675,6 +737,31 @@ void LCDFN(fillrect)(int x, int y, int width, int height)
675 /* adjust for viewport */ 737 /* adjust for viewport */
676 x += current_vp->x; 738 x += current_vp->x;
677 y += current_vp->y; 739 y += current_vp->y;
740
741#if defined(HAVE_VIEWPORT_CLIP)
742 /********************* Viewport on screen clipping ********************/
743 /* nothing to draw? */
744 if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
745 || (x + width <= 0) || (y + height <= 0))
746 return;
747
748 /* clip image in viewport in screen */
749 if (x < 0)
750 {
751 width += x;
752 x = 0;
753 }
754 if (y < 0)
755 {
756 height += y;
757 y = 0;
758 }
759 if (x + width > LCDM(WIDTH))
760 width = LCDM(WIDTH) - x;
761 if (y + height > LCDM(HEIGHT))
762 height = LCDM(HEIGHT) - y;
763#endif
764
678 765
679 if (current_vp->drawmode & DRMODE_INVERSEVID) 766 if (current_vp->drawmode & DRMODE_INVERSEVID)
680 { 767 {
@@ -751,12 +838,12 @@ void ICODE_ATTR LCDFN(mono_bitmap_part)(const unsigned char *src, int src_x,
751 unsigned data, mask, mask_bottom; 838 unsigned data, mask, mask_bottom;
752 LCDFN(blockfunc_type) *bfunc; 839 LCDFN(blockfunc_type) *bfunc;
753 840
841 /******************** Image in viewport clipping **********************/
754 /* nothing to draw? */ 842 /* nothing to draw? */
755 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) || 843 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) ||
756 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) 844 (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
757 return; 845 return;
758 846
759 /* clipping */
760 if (x < 0) 847 if (x < 0)
761 { 848 {
762 width += x; 849 width += x;
@@ -777,6 +864,32 @@ void ICODE_ATTR LCDFN(mono_bitmap_part)(const unsigned char *src, int src_x,
777 /* adjust for viewport */ 864 /* adjust for viewport */
778 x += current_vp->x; 865 x += current_vp->x;
779 y += current_vp->y; 866 y += current_vp->y;
867
868#if defined(HAVE_VIEWPORT_CLIP)
869 /********************* Viewport on screen clipping ********************/
870 /* nothing to draw? */
871 if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
872 || (x + width <= 0) || (y + height <= 0))
873 return;
874
875 /* clip image in viewport in screen */
876 if (x < 0)
877 {
878 width += x;
879 src_x -= x;
880 x = 0;
881 }
882 if (y < 0)
883 {
884 height += y;
885 src_y -= y;
886 y = 0;
887 }
888 if (x + width > LCDM(WIDTH))
889 width = LCDM(WIDTH) - x;
890 if (y + height > LCDM(HEIGHT))
891 height = LCDM(HEIGHT) - y;
892#endif
780 893
781 src += stride * (src_y >> 3) + src_x; /* move starting point */ 894 src += stride * (src_y >> 3) + src_x; /* move starting point */
782 src_y &= 7; 895 src_y &= 7;
@@ -893,12 +1006,12 @@ void ICODE_ATTR LCDFN(bitmap_part)(const FBFN(data) *src, int src_x,
893 FBFN(data) *dst, *dst_end; 1006 FBFN(data) *dst, *dst_end;
894 unsigned mask, mask_bottom; 1007 unsigned mask, mask_bottom;
895 1008
1009 /******************** Image in viewport clipping **********************/
896 /* nothing to draw? */ 1010 /* nothing to draw? */
897 if ((width <= 0) || (height <= 0) || (x >= current_vp->width) 1011 if ((width <= 0) || (height <= 0) || (x >= current_vp->width)
898 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0)) 1012 || (y >= current_vp->height) || (x + width <= 0) || (y + height <= 0))
899 return; 1013 return;
900 1014
901 /* clipping */
902 if (x < 0) 1015 if (x < 0)
903 { 1016 {
904 width += x; 1017 width += x;
@@ -920,6 +1033,32 @@ void ICODE_ATTR LCDFN(bitmap_part)(const FBFN(data) *src, int src_x,
920 x += current_vp->x; 1033 x += current_vp->x;
921 y += current_vp->y; 1034 y += current_vp->y;
922 1035
1036#if defined(HAVE_VIEWPORT_CLIP)
1037 /********************* Viewport on screen clipping ********************/
1038 /* nothing to draw? */
1039 if ((x >= LCDM(WIDTH)) || (y >= LCDM(HEIGHT))
1040 || (x + width <= 0) || (y + height <= 0))
1041 return;
1042
1043 /* clip image in viewport in screen */
1044 if (x < 0)
1045 {
1046 width += x;
1047 src_x -= x;
1048 x = 0;
1049 }
1050 if (y < 0)
1051 {
1052 height += y;
1053 src_y -= y;
1054 y = 0;
1055 }
1056 if (x + width > LCDM(WIDTH))
1057 width = LCDM(WIDTH) - x;
1058 if (y + height > LCDM(HEIGHT))
1059 height = LCDM(HEIGHT) - y;
1060#endif
1061
923 src += stride * (src_y >> 3) + src_x; /* move starting point */ 1062 src += stride * (src_y >> 3) + src_x; /* move starting point */
924 src_y &= 7; 1063 src_y &= 7;
925 y -= src_y; 1064 y -= src_y;
diff --git a/firmware/drivers/lcd-charcell.c b/firmware/drivers/lcd-charcell.c
index d02c5eeaad..9fabeb4a22 100644
--- a/firmware/drivers/lcd-charcell.c
+++ b/firmware/drivers/lcd-charcell.c
@@ -84,6 +84,28 @@ void lcd_set_viewport(struct viewport* vp)
84 current_vp = &default_vp; 84 current_vp = &default_vp;
85 else 85 else
86 current_vp = vp; 86 current_vp = vp;
87
88#if defined(SIMULATOR)
89 /* Force the viewport to be within bounds. If this happens it should
90 * be considered an error - the viewport will not draw as it might be
91 * expected.
92 */
93 if((unsigned) current_vp->x > (unsigned) LCD_WIDTH
94 || (unsigned) current_vp->y > (unsigned) LCD_HEIGHT
95 || current_vp->x + current_vp->width > LCD_WIDTH
96 || current_vp->y + current_vp->height > LCD_HEIGHT)
97 {
98#if !defined(HAVE_VIEWPORT_CLIP)
99 DEBUGF("ERROR: "
100#else
101 DEBUGF("NOTE: "
102#endif
103 "set_viewport out of bounds: x: %d y: %d width: %d height:%d\n",
104 current_vp->x, current_vp->y,
105 current_vp->width, current_vp->height);
106 }
107
108#endif
87} 109}
88 110
89void lcd_update_viewport(void) 111void lcd_update_viewport(void)
@@ -250,6 +272,11 @@ static void lcd_putxchar(int x, int y, int xchar)
250 x += current_vp->x; 272 x += current_vp->x;
251 y += current_vp->y; 273 y += current_vp->y;
252 274
275#if defined(HAVE_VIEWPORT_CLIP)
276 if((unsigned)x > (unsigned)LCD_WIDTH || (unsigned)y > (unsigned)LCD_HEIGHT)
277 return;
278#endif
279
253 lcd_char = lcd_charbuffer[y][x]; 280 lcd_char = lcd_charbuffer[y][x];
254 281
255 if (lcd_char < lcd_pattern_count) /* old char was soft */ 282 if (lcd_char < lcd_pattern_count) /* old char was soft */
diff --git a/firmware/export/config-mrobe500.h b/firmware/export/config-mrobe500.h
index 7b73fe7ad6..82ba8a8e83 100644
--- a/firmware/export/config-mrobe500.h
+++ b/firmware/export/config-mrobe500.h
@@ -65,6 +65,9 @@
65/* define this if the target has volume keys which can be used in the lists */ 65/* define this if the target has volume keys which can be used in the lists */
66#define HAVE_VOLUME_IN_LIST 66#define HAVE_VOLUME_IN_LIST
67 67
68/* define this if you want viewport clipping enabled for safe LCD functions */
69#define HAVE_VIEWPORT_CLIP
70
68/* LCD dimensions */ 71/* LCD dimensions */
69#define CONFIG_LCD LCD_MROBE500 72#define CONFIG_LCD LCD_MROBE500
70 73