Watchy icon indicating copy to clipboard operation
Watchy copied to clipboard

Bug: possible to end up with an incompletely-updated display (width calculation error)

Open dsalt opened this issue 11 months ago • 0 comments

I noticed this bug manifesting itself as the result of display.displayWindow(21, 20, 72, 15). This is not byte-aligned, with 3 pixels from the first byte and 5 from the last.

Internal calculations in the main WatchyDisplay::_writeImagePart code proceed as follows:

x -= x % 8; ⇒ mask off the bottom 3 bits (same as x &= ~7), giving 16. w = 8 * ((w + 7) / 8); ⇒ w = 8*((72+7)/8) = 8*(79/8) = 8*9 = 72.

This is now 72 pixels (or 72 bits) from X co-ordinate 16 rather than 72 pixels from X co-ordinate 21: the right edge is also shifted left by 5 pixels when it actually needs to be shifted 3 pixels right for byte alignment. The existing addition of 7 (given the subsequent division) would suffice if the rectangle were a little wider (between 73 and 77 pixels, in this case); but as the left edge is about to be moved left by 5 pixels, we need to add those 5 pixels to the width.

More generally, x & 7 (or x % 8, if you prefer) needs to be added before dividing by 8, which gives the following fix:

--- a/src/Display.cpp
+++ b/src/Display.cpp
@@ -182,8 +182,8 @@
   x_part -= x_part % 8; // byte boundary
   w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
   h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
+  w = 8 * ((w + (x & 7) + 7) / 8); // byte boundary, bitmaps are padded
   x -= x % 8; // byte boundary
-  w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
   int16_t x1 = x < 0 ? 0 : x; // limit
   int16_t y1 = y < 0 ? 0 : y; // limit
   int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit

(A similar change may be needed at line 114, in the main variant of WatchyDisplay::_writeImage.)

dsalt avatar Jan 17 '25 18:01 dsalt