acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

Arduino_GFX.cpp (86019B)

      1 /*
      2  * start rewrite from:
      3  * https://github.com/adafruit/Adafruit-GFX-Library.git
      4  *
      5  * Arc function come from:
      6  * https://github.com/lovyan03/LovyanGFX.git
      7  */
      8 #include "Arduino_DataBus.h"
      9 #include "Arduino_GFX.h"
     10 #include "font/glcdfont.h"
     11 #include "float.h"
     12 #ifdef __AVR__
     13 #include <avr/pgmspace.h>
     14 #elif defined(ESP8266) || defined(ESP32)
     15 #include <pgmspace.h>
     16 #endif
     17 
     18 /**************************************************************************/
     19 /*!
     20   @brief  Instatiate a GFX context for graphics! Can only be done by a superclass
     21   @param  w   Display width, in pixels
     22   @param  h   Display height, in pixels
     23 */
     24 /**************************************************************************/
     25 #if defined(LITTLE_FOOT_PRINT)
     26 Arduino_GFX::Arduino_GFX(int16_t w, int16_t h) : WIDTH(w), HEIGHT(h)
     27 #else
     28 Arduino_GFX::Arduino_GFX(int16_t w, int16_t h) : Arduino_G(w, h)
     29 #endif // !defined(LITTLE_FOOT_PRINT)
     30 {
     31   _width = WIDTH;
     32   _height = HEIGHT;
     33   _max_x = _width - 1;  ///< x zero base bound
     34   _max_y = _height - 1; ///< y zero base bound
     35   _rotation = 0;
     36   cursor_y = cursor_x = 0;
     37   textsize_x = textsize_y = 1;
     38   text_pixel_margin = 0;
     39   textcolor = textbgcolor = 0xFFFF;
     40   wrap = true;
     41 #if !defined(ATTINY_CORE)
     42   gfxFont = NULL;
     43 #if defined(U8G2_FONT_SUPPORT)
     44   u8g2Font = NULL;
     45 #endif // defined(U8G2_FONT_SUPPORT)
     46 #endif // !defined(ATTINY_CORE)
     47 }
     48 
     49 /**************************************************************************/
     50 /*!
     51   @brief  Write a line. Check straight or slash line and call corresponding function
     52   @param  x0      Start point x coordinate
     53   @param  y0      Start point y coordinate
     54   @param  x1      End point x coordinate
     55   @param  y1      End point y coordinate
     56   @param  color   16-bit 5-6-5 Color to draw with
     57 */
     58 /**************************************************************************/
     59 void Arduino_GFX::writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
     60                             uint16_t color)
     61 {
     62   if (x0 == x1)
     63   {
     64     if (y0 > y1)
     65     {
     66       _swap_int16_t(y0, y1);
     67     }
     68     writeFastVLine(x0, y0, y1 - y0 + 1, color);
     69   }
     70   else if (y0 == y1)
     71   {
     72     if (x0 > x1)
     73     {
     74       _swap_int16_t(x0, x1);
     75     }
     76     writeFastHLine(x0, y0, x1 - x0 + 1, color);
     77   }
     78   else
     79   {
     80     writeSlashLine(x0, y0, x1, y1, color);
     81   }
     82 }
     83 
     84 /**************************************************************************/
     85 /*!
     86   @brief  Write a line.  Bresenham's algorithm - thx wikpedia
     87   @param  x0      Start point x coordinate
     88   @param  y0      Start point y coordinate
     89   @param  x1      End point x coordinate
     90   @param  y1      End point y coordinate
     91   @param  color   16-bit 5-6-5 Color to draw with
     92 */
     93 /**************************************************************************/
     94 void Arduino_GFX::writeSlashLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
     95                                  uint16_t color)
     96 {
     97   bool steep = _diff(y1, y0) > _diff(x1, x0);
     98   if (steep)
     99   {
    100     _swap_int16_t(x0, y0);
    101     _swap_int16_t(x1, y1);
    102   }
    103 
    104   if (x0 > x1)
    105   {
    106     _swap_int16_t(x0, x1);
    107     _swap_int16_t(y0, y1);
    108   }
    109 
    110   int16_t dx = x1 - x0;
    111   int16_t dy = _diff(y1, y0);
    112   int16_t err = dx >> 1;
    113   int16_t step = (y0 < y1) ? 1 : -1;
    114 
    115   for (; x0 <= x1; x0++)
    116   {
    117     if (steep)
    118     {
    119       writePixel(y0, x0, color);
    120     }
    121     else
    122     {
    123       writePixel(x0, y0, color);
    124     }
    125     err -= dy;
    126     if (err < 0)
    127     {
    128       err += dx;
    129       y0 += step;
    130     }
    131   }
    132 }
    133 
    134 /**************************************************************************/
    135 /*!
    136   @brief  Start a display-writing routine, overwrite in subclasses.
    137 */
    138 /**************************************************************************/
    139 INLINE void Arduino_GFX::startWrite()
    140 {
    141 }
    142 
    143 void Arduino_GFX::writePixel(int16_t x, int16_t y, uint16_t color)
    144 {
    145   if (_ordered_in_range(x, 0, _max_x) && _ordered_in_range(y, 0, _max_y))
    146   {
    147     writePixelPreclipped(x, y, color);
    148   }
    149 }
    150 
    151 /**************************************************************************/
    152 /*!
    153   @brief  Write a pixel, overwrite in subclasses if startWrite is defined!
    154   @param  x       x coordinate
    155   @param  y       y coordinate
    156   @param  color   16-bit 5-6-5 Color to fill with
    157 */
    158 /**************************************************************************/
    159 void Arduino_GFX::drawPixel(int16_t x, int16_t y, uint16_t color)
    160 {
    161   startWrite();
    162   writePixel(x, y, color);
    163   endWrite();
    164 }
    165 
    166 /**************************************************************************/
    167 /*!
    168   @brief  Write a perfectly vertical line, overwrite in subclasses if startWrite is defined!
    169   @param  x       Top-most x coordinate
    170   @param  y       Top-most y coordinate
    171   @param  h       Height in pixels
    172   @param  color   16-bit 5-6-5 Color to fill with
    173 */
    174 /**************************************************************************/
    175 void Arduino_GFX::writeFastVLine(int16_t x, int16_t y,
    176                                  int16_t h, uint16_t color)
    177 {
    178   for (int16_t i = y; i < y + h; i++)
    179   {
    180     writePixel(x, i, color);
    181   }
    182 }
    183 
    184 /**************************************************************************/
    185 /*!
    186   @brief  Write a perfectly horizontal line, overwrite in subclasses if startWrite is defined!
    187   @param  x       Left-most x coordinate
    188   @param  y       Left-most y coordinate
    189   @param  w       Width in pixels
    190   @param  color   16-bit 5-6-5 Color to fill with
    191 */
    192 /**************************************************************************/
    193 void Arduino_GFX::writeFastHLine(int16_t x, int16_t y,
    194                                  int16_t w, uint16_t color)
    195 {
    196   for (int16_t i = x; i < x + w; i++)
    197   {
    198     writePixel(i, y, color);
    199   }
    200 }
    201 
    202 /**************************************************************************/
    203 /*!
    204   @brief  Draw a filled rectangle to the display. Not self-contained;
    205     should follow startWrite(). Typically used by higher-level
    206     graphics primitives; user code shouldn't need to call this and
    207     is likely to use the self-contained fillRect() instead.
    208     writeFillRect() performs its own edge clipping and rejection;
    209     see writeFillRectPreclipped() for a more 'raw' implementation.
    210   @param  x       Horizontal position of first corner.
    211   @param  y       Vertical position of first corner.
    212   @param  w       Rectangle width in pixels (positive = right of first
    213       corner, negative = left of first corner).
    214   @param  h       Rectangle height in pixels (positive = below first
    215       corner, negative = above first corner).
    216   @param  color   16-bit fill color in '565' RGB format.
    217   @note   Written in this deep-nested way because C by definition will
    218     optimize for the 'if' case, not the 'else' -- avoids branches
    219     and rejects clipped rectangles at the least-work possibility.
    220 */
    221 /**************************************************************************/
    222 void Arduino_GFX::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h,
    223                                 uint16_t color)
    224 {
    225   if (w && h)
    226   { // Nonzero width and height?
    227     if (w < 0)
    228     {             // If negative width...
    229       x += w + 1; //   Move X to left edge
    230       w = -w;     //   Use positive width
    231     }
    232     if (x <= _max_x)
    233     { // Not off right
    234       if (h < 0)
    235       {             // If negative height...
    236         y += h + 1; //   Move Y to top edge
    237         h = -h;     //   Use positive height
    238       }
    239       if (y <= _max_y)
    240       { // Not off bottom
    241         int16_t x2 = x + w - 1;
    242         if (x2 >= 0)
    243         { // Not off left
    244           int16_t y2 = y + h - 1;
    245           if (y2 >= 0)
    246           { // Not off top
    247             // Rectangle partly or fully overlaps screen
    248             if (x < 0)
    249             {
    250               x = 0;
    251               w = x2 + 1;
    252             } // Clip left
    253             if (y < 0)
    254             {
    255               y = 0;
    256               h = y2 + 1;
    257             } // Clip top
    258             if (x2 > _max_x)
    259             {
    260               w = _max_x - x + 1;
    261             } // Clip right
    262             if (y2 > _max_y)
    263             {
    264               h = _max_y - y + 1;
    265             } // Clip bottom
    266             writeFillRectPreclipped(x, y, w, h, color);
    267           }
    268         }
    269       }
    270     }
    271   }
    272 }
    273 
    274 /**************************************************************************/
    275 /*!
    276   @brief  Write a rectangle completely with one color, overwrite in subclasses if startWrite is defined!
    277   @param  x       Top left corner x coordinate
    278   @param  y       Top left corner y coordinate
    279   @param  w       Width in pixels
    280   @param  h       Height in pixels
    281   @param  color   16-bit 5-6-5 Color to fill with
    282 */
    283 /**************************************************************************/
    284 void Arduino_GFX::writeFillRectPreclipped(int16_t x, int16_t y, int16_t w, int16_t h,
    285                                           uint16_t color)
    286 {
    287   // Overwrite in subclasses if desired!
    288   for (int16_t i = y; i < y + h; i++)
    289   {
    290     writeFastHLine(x, i, w, color);
    291   }
    292 }
    293 
    294 /**************************************************************************/
    295 /*!
    296   @brief  End a display-writing routine, overwrite in subclasses if startWrite is defined!
    297 */
    298 /**************************************************************************/
    299 INLINE void Arduino_GFX::endWrite()
    300 {
    301 }
    302 
    303 /**************************************************************************/
    304 /*!
    305   @brief  Draw a perfectly vertical line (this is often optimized in a subclass!)
    306   @param  x       Top-most x coordinate
    307   @param  y       Top-most y coordinate
    308   @param  h       Height in pixels
    309   @param  color   16-bit 5-6-5 Color to fill with
    310 */
    311 /**************************************************************************/
    312 void Arduino_GFX::drawFastVLine(int16_t x, int16_t y,
    313                                 int16_t h, uint16_t color)
    314 {
    315   startWrite();
    316   writeFastVLine(x, y, h, color);
    317   endWrite();
    318 }
    319 
    320 /**************************************************************************/
    321 /*!
    322   @brief  Draw a perfectly horizontal line (this is often optimized in a subclass!)
    323   @param  x       Left-most x coordinate
    324   @param  y       Left-most y coordinate
    325   @param  w       Width in pixels
    326   @param  color   16-bit 5-6-5 Color to fill with
    327 */
    328 /**************************************************************************/
    329 void Arduino_GFX::drawFastHLine(int16_t x, int16_t y,
    330                                 int16_t w, uint16_t color)
    331 {
    332   startWrite();
    333   writeFastHLine(x, y, w, color);
    334   endWrite();
    335 }
    336 
    337 /**************************************************************************/
    338 /*!
    339   @brief  Fill a rectangle completely with one color. Update in subclasses if desired!
    340   @param  x       Top left corner x coordinate
    341   @param  y       Top left corner y coordinate
    342   @param  w       Width in pixels
    343   @param  h       Height in pixels
    344   @param  color   16-bit 5-6-5 Color to fill with
    345 */
    346 /**************************************************************************/
    347 void Arduino_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
    348                            uint16_t color)
    349 {
    350   startWrite();
    351   writeFillRect(x, y, w, h, color);
    352   endWrite();
    353 }
    354 
    355 /**************************************************************************/
    356 /*!
    357   @brief  Fill the screen completely with one color. Update in subclasses if desired!
    358   @param  color 16-bit 5-6-5 Color to fill with
    359 */
    360 /**************************************************************************/
    361 void Arduino_GFX::fillScreen(uint16_t color)
    362 {
    363   fillRect(0, 0, _width, _height, color);
    364 }
    365 
    366 /**************************************************************************/
    367 /*!
    368   @brief  Draw a line
    369   @param  x0      Start point x coordinate
    370   @param  y0      Start point y coordinate
    371   @param  x1      End point x coordinate
    372   @param  y1      End point y coordinate
    373   @param  color   16-bit 5-6-5 Color to draw with
    374 */
    375 /**************************************************************************/
    376 void Arduino_GFX::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
    377                            uint16_t color)
    378 {
    379   // Update in subclasses if desired!
    380   startWrite();
    381   writeLine(x0, y0, x1, y1, color);
    382   endWrite();
    383 }
    384 
    385 /**************************************************************************/
    386 /*!
    387   @brief  Draw a circle outline
    388   @param  x       Center-point x coordinate
    389   @param  y       Center-point y coordinate
    390   @param  r       Radius of circle
    391   @param  color   16-bit 5-6-5 Color to draw with
    392 */
    393 /**************************************************************************/
    394 void Arduino_GFX::drawCircle(int16_t x, int16_t y,
    395                              int16_t r, uint16_t color)
    396 {
    397   startWrite();
    398   drawEllipseHelper(x, y, r, r, 0xf, color);
    399   endWrite();
    400 }
    401 
    402 /**************************************************************************/
    403 /*!
    404   @brief  Quarter-ellipse drawer, used to do circles and roundrects
    405   @param  x           Center-point x coordinate
    406   @param  y           Center-point y coordinate
    407   @param  rx          radius of x coordinate
    408   @param  ry          radius of y coordinate
    409   @param  cornername  Mask bit #1 or bit #2 to indicate which quarters of the circle we're doing
    410   @param  color       16-bit 5-6-5 Color to draw with
    411 */
    412 /**************************************************************************/
    413 void Arduino_GFX::drawEllipseHelper(int32_t x, int32_t y,
    414                                     int32_t rx, int32_t ry,
    415                                     uint8_t cornername, uint16_t color)
    416 {
    417   if (rx < 0 || ry < 0 || ((rx == 0) && (ry == 0)))
    418   {
    419     return;
    420   }
    421   if (ry == 0)
    422   {
    423     drawFastHLine(x - rx, y, (ry << 2) + 1, color);
    424     return;
    425   }
    426   if (rx == 0)
    427   {
    428     drawFastVLine(x, y - ry, (rx << 2) + 1, color);
    429     return;
    430   }
    431 
    432   int32_t xt, yt, s, i;
    433   int32_t rx2 = rx * rx;
    434   int32_t ry2 = ry * ry;
    435 
    436   i = -1;
    437   xt = 0;
    438   yt = ry;
    439   s = (ry2 << 1) + rx2 * (1 - (ry << 1));
    440   do
    441   {
    442     while (s < 0)
    443       s += ry2 * ((++xt << 2) + 2);
    444     if (cornername & 0x1)
    445     {
    446       writeFastHLine(x - xt, y - yt, xt - i, color);
    447     }
    448     if (cornername & 0x2)
    449     {
    450       writeFastHLine(x + i + 1, y - yt, xt - i, color);
    451     }
    452     if (cornername & 0x4)
    453     {
    454       writeFastHLine(x + i + 1, y + yt, xt - i, color);
    455     }
    456     if (cornername & 0x8)
    457     {
    458       writeFastHLine(x - xt, y + yt, xt - i, color);
    459     }
    460     i = xt;
    461     s -= (--yt) * rx2 << 2;
    462   } while (ry2 * xt <= rx2 * yt);
    463 
    464   i = -1;
    465   yt = 0;
    466   xt = rx;
    467   s = (rx2 << 1) + ry2 * (1 - (rx << 1));
    468   do
    469   {
    470     while (s < 0)
    471       s += rx2 * ((++yt << 2) + 2);
    472     if (cornername & 0x1)
    473     {
    474       writeFastVLine(x - xt, y - yt, yt - i, color);
    475     }
    476     if (cornername & 0x2)
    477     {
    478       writeFastVLine(x + xt, y - yt, yt - i, color);
    479     }
    480     if (cornername & 0x4)
    481     {
    482       writeFastVLine(x + xt, y + i + 1, yt - i, color);
    483     }
    484     if (cornername & 0x8)
    485     {
    486       writeFastVLine(x - xt, y + i + 1, yt - i, color);
    487     }
    488     i = yt;
    489     s -= (--xt) * ry2 << 2;
    490   } while (rx2 * yt <= ry2 * xt);
    491 }
    492 
    493 /**************************************************************************/
    494 /*!
    495   @brief  Draw a circle with filled color
    496   @param  x       Center-point x coordinate
    497   @param  y       Center-point y coordinate
    498   @param  r       Radius of circle
    499   @param  color   16-bit 5-6-5 Color to fill with
    500 */
    501 /**************************************************************************/
    502 void Arduino_GFX::fillCircle(int16_t x, int16_t y,
    503                              int16_t r, uint16_t color)
    504 {
    505   startWrite();
    506   fillEllipseHelper(x, y, r, r, 3, 0, color);
    507   endWrite();
    508 }
    509 
    510 /**************************************************************************/
    511 /*!
    512   @brief  Quarter-circle drawer with fill, used for circles and roundrects
    513   @param  x       Center-point x coordinate
    514   @param  y       Center-point y coordinate
    515   @param  rx      Radius of x coordinate
    516   @param  ry      Radius of y coordinate
    517   @param  corners Mask bits indicating which quarters we're doing
    518   @param  delta   Offset from center-point, used for round-rects
    519   @param  color   16-bit 5-6-5 Color to fill with
    520 */
    521 /**************************************************************************/
    522 void Arduino_GFX::fillEllipseHelper(int32_t x, int32_t y,
    523                                     int32_t rx, int32_t ry,
    524                                     uint8_t corners, int16_t delta, uint16_t color)
    525 {
    526   if (rx < 0 || ry < 0 || ((rx == 0) && (ry == 0)))
    527   {
    528     return;
    529   }
    530   if (ry == 0)
    531   {
    532     drawFastHLine(x - rx, y, (ry << 2) + 1, color);
    533     return;
    534   }
    535   if (rx == 0)
    536   {
    537     drawFastVLine(x, y - ry, (rx << 2) + 1, color);
    538     return;
    539   }
    540 
    541   int32_t xt, yt, i;
    542   int32_t rx2 = (int32_t)rx * rx;
    543   int32_t ry2 = (int32_t)ry * ry;
    544   int32_t s;
    545 
    546   writeFastHLine(x - rx, y, (rx << 1) + 1, color);
    547   i = 0;
    548   yt = 0;
    549   xt = rx;
    550   s = (rx2 << 1) + ry2 * (1 - (rx << 1));
    551   do
    552   {
    553     while (s < 0)
    554     {
    555       s += rx2 * ((++yt << 2) + 2);
    556     }
    557     if (corners & 1)
    558     {
    559       writeFillRect(x - xt, y - yt, (xt << 1) + 1 + delta, yt - i, color);
    560     }
    561     if (corners & 2)
    562     {
    563       writeFillRect(x - xt, y + i + 1, (xt << 1) + 1 + delta, yt - i, color);
    564     }
    565     i = yt;
    566     s -= (--xt) * ry2 << 2;
    567   } while (rx2 * yt <= ry2 * xt);
    568 
    569   xt = 0;
    570   yt = ry;
    571   s = (ry2 << 1) + rx2 * (1 - (ry << 1));
    572   do
    573   {
    574     while (s < 0)
    575     {
    576       s += ry2 * ((++xt << 2) + 2);
    577     }
    578     if (corners & 1)
    579     {
    580       writeFastHLine(x - xt, y - yt, (xt << 1) + 1 + delta, color);
    581     }
    582     if (corners & 2)
    583     {
    584       writeFastHLine(x - xt, y + yt, (xt << 1) + 1 + delta, color);
    585     }
    586     s -= (--yt) * rx2 << 2;
    587   } while (ry2 * xt <= rx2 * yt);
    588 }
    589 
    590 /**************************************************************************/
    591 /*!
    592   @brief  Draw an ellipse outline
    593   @param  x       Center-point x coordinate
    594   @param  y       Center-point y coordinate
    595   @param  rx      radius of x coordinate
    596   @param  ry      radius of y coordinate
    597   @param  start   degree of ellipse start
    598   @param  end     degree of ellipse end
    599   @param  color   16-bit 5-6-5 Color to draw with
    600 */
    601 /**************************************************************************/
    602 void Arduino_GFX::drawEllipse(int16_t x, int16_t y, int16_t rx, int16_t ry, uint16_t color)
    603 {
    604   startWrite();
    605   drawEllipseHelper(x, y, rx, ry, 0xf, color);
    606   endWrite();
    607 }
    608 
    609 /**************************************************************************/
    610 /*!
    611   @brief  Draw an ellipse with filled color
    612   @param  x       Center-point x coordinate
    613   @param  y       Center-point y coordinate
    614   @param  rx      radius of x coordinate
    615   @param  ry      radius of y coordinate
    616   @param  start   degree of ellipse start
    617   @param  end     degree of ellipse end
    618   @param  color   16-bit 5-6-5 Color to fill with
    619 */
    620 /**************************************************************************/
    621 void Arduino_GFX::fillEllipse(int16_t x, int16_t y, int16_t rx, int16_t ry, uint16_t color)
    622 {
    623   startWrite();
    624   fillEllipseHelper(x, y, rx, ry, 3, 0, color);
    625   endWrite();
    626 }
    627 
    628 /**************************************************************************/
    629 /*!
    630   @brief  Draw an arc outline
    631   @param  x       Center-point x coordinate
    632   @param  y       Center-point y coordinate
    633   @param  r1      Outer radius of arc
    634   @param  r2      Inner radius of arc
    635   @param  start   degree of arc start
    636   @param  end     degree of arc end
    637   @param  color   16-bit 5-6-5 Color to draw with
    638 */
    639 /**************************************************************************/
    640 void Arduino_GFX::drawArc(int16_t x, int16_t y, int16_t r1, int16_t r2, float start, float end, uint16_t color)
    641 {
    642   if (r1 < r2)
    643   {
    644     _swap_int16_t(r1, r2);
    645   }
    646   if (r1 < 1)
    647   {
    648     r1 = 1;
    649   }
    650   if (r2 < 1)
    651   {
    652     r2 = 1;
    653   }
    654   bool equal = fabsf(start - end) < FLT_EPSILON;
    655   start = fmodf(start, 360);
    656   end = fmodf(end, 360);
    657   if (start < 0)
    658     start += 360.0;
    659   if (end < 0)
    660     end += 360.0;
    661 
    662   startWrite();
    663   fillArcHelper(x, y, r1, r2, start, start, color);
    664   fillArcHelper(x, y, r1, r2, end, end, color);
    665   if (!equal && (fabsf(start - end) <= 0.0001))
    666   {
    667     start = .0;
    668     end = 360.0;
    669   }
    670   fillArcHelper(x, y, r1, r1, start, end, color);
    671   fillArcHelper(x, y, r2, r2, start, end, color);
    672   endWrite();
    673 }
    674 
    675 /**************************************************************************/
    676 /*!
    677   @brief  Draw an arc with filled color
    678   @param  x       Center-point x coordinate
    679   @param  y       Center-point y coordinate
    680   @param  r1      Outer radius of arc
    681   @param  r2      Inner radius of arc
    682   @param  start   degree of arc start
    683   @param  end     degree of arc end
    684   @param  color   16-bit 5-6-5 Color to fill with
    685 */
    686 /**************************************************************************/
    687 void Arduino_GFX::fillArc(int16_t x, int16_t y, int16_t r1, int16_t r2, float start, float end, uint16_t color)
    688 {
    689   if (r1 < r2)
    690   {
    691     _swap_int16_t(r1, r2);
    692   }
    693   if (r1 < 1)
    694   {
    695     r1 = 1;
    696   }
    697   if (r2 < 1)
    698   {
    699     r2 = 1;
    700   }
    701   bool equal = fabsf(start - end) < FLT_EPSILON;
    702   start = fmodf(start, 360);
    703   end = fmodf(end, 360);
    704   if (start < 0)
    705     start += 360.0;
    706   if (end < 0)
    707     end += 360.0;
    708   if (!equal && (fabsf(start - end) <= 0.0001))
    709   {
    710     start = .0;
    711     end = 360.0;
    712   }
    713 
    714   startWrite();
    715   fillArcHelper(x, y, r1, r2, start, end, color);
    716   endWrite();
    717 }
    718 
    719 /**************************************************************************/
    720 /*!
    721   @brief  Arc drawer with fill
    722   @param  cx      Center-point x coordinate
    723   @param  cy      Center-point y coordinate
    724   @param  oradius Outer radius of arc
    725   @param  iradius Inner radius of arc
    726   @param  start   degree of arc start
    727   @param  end     degree of arc end
    728   @param  color   16-bit 5-6-5 Color to fill with
    729 */
    730 /**************************************************************************/
    731 void Arduino_GFX::fillArcHelper(int16_t cx, int16_t cy, int16_t oradius, int16_t iradius, float start, float end, uint16_t color)
    732 {
    733   if ((start == 90.0) || (start == 180.0) || (start == 270.0) || (start == 360.0))
    734   {
    735     start -= 0.1;
    736   }
    737 
    738   if ((end == 90.0) || (end == 180.0) || (end == 270.0) || (end == 360.0))
    739   {
    740     end -= 0.1;
    741   }
    742 
    743   float s_cos = (cos(start * DEGTORAD));
    744   float e_cos = (cos(end * DEGTORAD));
    745   float sslope = s_cos / (sin(start * DEGTORAD));
    746   float eslope = e_cos / (sin(end * DEGTORAD));
    747   float swidth = 0.5 / s_cos;
    748   float ewidth = -0.5 / e_cos;
    749   --iradius;
    750   int32_t ir2 = iradius * iradius + iradius;
    751   int32_t or2 = oradius * oradius + oradius;
    752 
    753   bool start180 = !(start < 180.0);
    754   bool end180 = end < 180.0;
    755   bool reversed = start + 180.0 < end || (end < start && start < end + 180.0);
    756 
    757   int32_t xs = -oradius;
    758   int32_t y = -oradius;
    759   int32_t ye = oradius;
    760   int32_t xe = oradius + 1;
    761   if (!reversed)
    762   {
    763     if ((end >= 270 || end < 90) && (start >= 270 || start < 90))
    764     {
    765       xs = 0;
    766     }
    767     else if (end < 270 && end >= 90 && start < 270 && start >= 90)
    768     {
    769       xe = 1;
    770     }
    771     if (end >= 180 && start >= 180)
    772     {
    773       ye = 0;
    774     }
    775     else if (end < 180 && start < 180)
    776     {
    777       y = 0;
    778     }
    779   }
    780   do
    781   {
    782     int32_t y2 = y * y;
    783     int32_t x = xs;
    784     if (x < 0)
    785     {
    786       while (x * x + y2 >= or2)
    787       {
    788         ++x;
    789       }
    790       if (xe != 1)
    791       {
    792         xe = 1 - x;
    793       }
    794     }
    795     float ysslope = (y + swidth) * sslope;
    796     float yeslope = (y + ewidth) * eslope;
    797     int32_t len = 0;
    798     do
    799     {
    800       bool flg1 = start180 != (x <= ysslope);
    801       bool flg2 = end180 != (x <= yeslope);
    802       int32_t distance = x * x + y2;
    803       if (distance >= ir2 && ((flg1 && flg2) || (reversed && (flg1 || flg2))) && x != xe && distance < or2)
    804       {
    805         ++len;
    806       }
    807       else
    808       {
    809         if (len)
    810         {
    811           writeFastHLine(cx + x - len, cy + y, len, color);
    812           len = 0;
    813         }
    814         if (distance >= or2)
    815           break;
    816         if (x < 0 && distance < ir2)
    817         {
    818           x = -x;
    819         }
    820       }
    821     } while (++x <= xe);
    822   } while (++y <= ye);
    823 }
    824 
    825 /**************************************************************************/
    826 /*!
    827   @brief  Draw a rectangle with no fill color
    828   @param  x       Top left corner x coordinate
    829   @param  y       Top left corner y coordinate
    830   @param  w       Width in pixels
    831   @param  h       Height in pixels
    832   @param  color   16-bit 5-6-5 Color to draw with
    833 */
    834 /**************************************************************************/
    835 void Arduino_GFX::drawRect(int16_t x, int16_t y, int16_t w, int16_t h,
    836                            uint16_t color)
    837 {
    838   startWrite();
    839   writeFastHLine(x, y, w, color);
    840   writeFastHLine(x, y + h - 1, w, color);
    841   writeFastVLine(x, y, h, color);
    842   writeFastVLine(x + w - 1, y, h, color);
    843   endWrite();
    844 }
    845 
    846 /**************************************************************************/
    847 /*!
    848   @brief  Draw a rounded rectangle with no fill color
    849   @param  x       Top left corner x coordinate
    850   @param  y       Top left corner y coordinate
    851   @param  w       Width in pixels
    852   @param  h       Height in pixels
    853   @param  r       Radius of corner rounding
    854   @param  color   16-bit 5-6-5 Color to draw with
    855 */
    856 /**************************************************************************/
    857 void Arduino_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w,
    858                                 int16_t h, int16_t r, uint16_t color)
    859 {
    860   int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
    861   if (r > max_radius)
    862     r = max_radius;
    863   // smarter version
    864   startWrite();
    865   writeFastHLine(x + r, y, w - 2 * r, color);         // Top
    866   writeFastHLine(x + r, y + h - 1, w - 2 * r, color); // Bottom
    867   writeFastVLine(x, y + r, h - 2 * r, color);         // Left
    868   writeFastVLine(x + w - 1, y + r, h - 2 * r, color); // Right
    869   // draw four corners
    870   drawEllipseHelper(x + r, y + r, r, r, 1, color);
    871   drawEllipseHelper(x + w - r - 1, y + r, r, r, 2, color);
    872   drawEllipseHelper(x + w - r - 1, y + h - r - 1, r, r, 4, color);
    873   drawEllipseHelper(x + r, y + h - r - 1, r, r, 8, color);
    874   endWrite();
    875 }
    876 
    877 /**************************************************************************/
    878 /*!
    879   @brief  Draw a rounded rectangle with fill color
    880   @param  x       Top left corner x coordinate
    881   @param  y       Top left corner y coordinate
    882   @param  w       Width in pixels
    883   @param  h       Height in pixels
    884   @param  r       Radius of corner rounding
    885   @param  color   16-bit 5-6-5 Color to draw/fill with
    886 */
    887 /**************************************************************************/
    888 void Arduino_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w,
    889                                 int16_t h, int16_t r, uint16_t color)
    890 {
    891   int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
    892   if (r > max_radius)
    893     r = max_radius;
    894   // smarter version
    895   startWrite();
    896   writeFillRect(x, y + r, w, h - (r << 1), color);
    897   // draw four corners
    898   fillEllipseHelper(x + r, y + r, r, r, 1, w - 2 * r - 1, color);
    899   fillEllipseHelper(x + r, y + h - r - 1, r, r, 2, w - 2 * r - 1, color);
    900   endWrite();
    901 }
    902 
    903 /**************************************************************************/
    904 /*!
    905   @brief  Draw a triangle with no fill color
    906   @param  x0      Vertex #0 x coordinate
    907   @param  y0      Vertex #0 y coordinate
    908   @param  x1      Vertex #1 x coordinate
    909   @param  y1      Vertex #1 y coordinate
    910   @param  x2      Vertex #2 x coordinate
    911   @param  y2      Vertex #2 y coordinate
    912   @param  color   16-bit 5-6-5 Color to draw with
    913 */
    914 /**************************************************************************/
    915 void Arduino_GFX::drawTriangle(int16_t x0, int16_t y0,
    916                                int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color)
    917 {
    918   startWrite();
    919   writeLine(x0, y0, x1, y1, color);
    920   writeLine(x1, y1, x2, y2, color);
    921   writeLine(x2, y2, x0, y0, color);
    922   endWrite();
    923 }
    924 
    925 /**************************************************************************/
    926 /*!
    927   @brief  Draw a triangle with color-fill
    928   @param  x0      Vertex #0 x coordinate
    929   @param  y0      Vertex #0 y coordinate
    930   @param  x1      Vertex #1 x coordinate
    931   @param  y1      Vertex #1 y coordinate
    932   @param  x2      Vertex #2 x coordinate
    933   @param  y2      Vertex #2 y coordinate
    934   @param  color   16-bit 5-6-5 Color to fill/draw with
    935 */
    936 /**************************************************************************/
    937 void Arduino_GFX::fillTriangle(int16_t x0, int16_t y0,
    938                                int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color)
    939 {
    940   int16_t a, b, y, last;
    941 
    942   // Sort coordinates by Y order (y2 >= y1 >= y0)
    943   if (y0 > y1)
    944   {
    945     _swap_int16_t(y0, y1);
    946     _swap_int16_t(x0, x1);
    947   }
    948   if (y1 > y2)
    949   {
    950     _swap_int16_t(y2, y1);
    951     _swap_int16_t(x2, x1);
    952   }
    953   if (y0 > y1)
    954   {
    955     _swap_int16_t(y0, y1);
    956     _swap_int16_t(x0, x1);
    957   }
    958 
    959   startWrite();
    960   if (y0 == y2)
    961   { // Handle awkward all-on-same-line case as its own thing
    962     a = b = x0;
    963     if (x1 < a)
    964       a = x1;
    965     else if (x1 > b)
    966       b = x1;
    967     if (x2 < a)
    968       a = x2;
    969     else if (x2 > b)
    970       b = x2;
    971     writeFastHLine(a, y0, b - a + 1, color);
    972     endWrite();
    973     return;
    974   }
    975 
    976   int16_t
    977       dx01 = x1 - x0,
    978       dy01 = y1 - y0,
    979       dx02 = x2 - x0,
    980       dy02 = y2 - y0,
    981       dx12 = x2 - x1,
    982       dy12 = y2 - y1;
    983   int32_t
    984       sa = 0,
    985       sb = 0;
    986 
    987   // For upper part of triangle, find scanline crossings for segments
    988   // 0-1 and 0-2.  If y1=y2 (flat-bottomed triangle), the scanline y1
    989   // is included here (and second loop will be skipped, avoiding a /0
    990   // error there), otherwise scanline y1 is skipped here and handled
    991   // in the second loop...which also avoids a /0 error here if y0=y1
    992   // (flat-topped triangle).
    993   if (y1 == y2)
    994   {
    995     last = y1; // Include y1 scanline
    996   }
    997   else
    998   {
    999     last = y1 - 1; // Skip it
   1000   }
   1001 
   1002   for (y = y0; y <= last; y++)
   1003   {
   1004     a = x0 + sa / dy01;
   1005     b = x0 + sb / dy02;
   1006     sa += dx01;
   1007     sb += dx02;
   1008     /* longhand:
   1009     a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
   1010     b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
   1011     */
   1012     if (a > b)
   1013     {
   1014       _swap_int16_t(a, b);
   1015     }
   1016     writeFastHLine(a, y, b - a + 1, color);
   1017   }
   1018 
   1019   // For lower part of triangle, find scanline crossings for segments
   1020   // 0-2 and 1-2.  This loop is skipped if y1=y2.
   1021   sa = (int32_t)dx12 * (y - y1);
   1022   sb = (int32_t)dx02 * (y - y0);
   1023   for (; y <= y2; y++)
   1024   {
   1025     a = x1 + sa / dy12;
   1026     b = x0 + sb / dy02;
   1027     sa += dx12;
   1028     sb += dx02;
   1029     /* longhand:
   1030     a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
   1031     b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
   1032     */
   1033     if (a > b)
   1034     {
   1035       _swap_int16_t(a, b);
   1036     }
   1037     writeFastHLine(a, y, b - a + 1, color);
   1038   }
   1039   endWrite();
   1040 }
   1041 
   1042 // BITMAP / XBITMAP / GRAYSCALE / RGB BITMAP FUNCTIONS ---------------------
   1043 
   1044 /**************************************************************************/
   1045 /*!
   1046   @brief  Draw a PROGMEM-resident 1-bit image at the specified (x,y) position, using the specified foreground color (unset bits are transparent).
   1047   @param  x       Top left corner x coordinate
   1048   @param  y       Top left corner y coordinate
   1049   @param  bitmap  byte array with monochrome bitmap
   1050   @param  w       Width of bitmap in pixels
   1051   @param  h       Height of bitmap in pixels
   1052   @param  color   16-bit 5-6-5 Color to draw with
   1053 */
   1054 /**************************************************************************/
   1055 void Arduino_GFX::drawBitmap(int16_t x, int16_t y,
   1056                              const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color)
   1057 {
   1058   int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
   1059   uint8_t byte = 0;
   1060 
   1061   startWrite();
   1062   for (int16_t j = 0; j < h; j++, y++)
   1063   {
   1064     for (int16_t i = 0; i < w; i++)
   1065     {
   1066       if (i & 7)
   1067       {
   1068         byte <<= 1;
   1069       }
   1070       else
   1071       {
   1072         byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
   1073       }
   1074       if (byte & 0x80)
   1075       {
   1076         writePixel(x + i, y, color);
   1077       }
   1078     }
   1079   }
   1080   endWrite();
   1081 }
   1082 
   1083 /**************************************************************************/
   1084 /*!
   1085   @brief  Draw a PROGMEM-resident 1-bit image at the specified (x,y) position, using the specified foreground (for set bits) and background (unset bits) colors.
   1086   @param  x       Top left corner x coordinate
   1087   @param  y       Top left corner y coordinate
   1088   @param  bitmap  byte array with monochrome bitmap
   1089   @param  w       Width of bitmap in pixels
   1090   @param  h       Height of bitmap in pixels
   1091   @param  color   16-bit 5-6-5 Color to draw pixels with
   1092   @param  bg      16-bit 5-6-5 Color to draw background with
   1093 */
   1094 /**************************************************************************/
   1095 void Arduino_GFX::drawBitmap(int16_t x, int16_t y,
   1096                              const uint8_t bitmap[], int16_t w, int16_t h,
   1097                              uint16_t color, uint16_t bg)
   1098 {
   1099   int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
   1100   uint8_t byte = 0;
   1101 
   1102   startWrite();
   1103   for (int16_t j = 0; j < h; j++, y++)
   1104   {
   1105     for (int16_t i = 0; i < w; i++)
   1106     {
   1107       if (i & 7)
   1108       {
   1109         byte <<= 1;
   1110       }
   1111       else
   1112       {
   1113         byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
   1114       }
   1115       writePixel(x + i, y, (byte & 0x80) ? color : bg);
   1116     }
   1117   }
   1118   endWrite();
   1119 }
   1120 
   1121 /**************************************************************************/
   1122 /*!
   1123   @brief  Draw a RAM-resident 1-bit image at the specified (x,y) position, using the specified foreground color (unset bits are transparent).
   1124   @param  x       Top left corner x coordinate
   1125   @param  y       Top left corner y coordinate
   1126   @param  bitmap  byte array with monochrome bitmap
   1127   @param  w       Width of bitmap in pixels
   1128   @param  h       Height of bitmap in pixels
   1129   @param  color   16-bit 5-6-5 Color to draw with
   1130 */
   1131 /**************************************************************************/
   1132 void Arduino_GFX::drawBitmap(int16_t x, int16_t y,
   1133                              uint8_t *bitmap, int16_t w, int16_t h, uint16_t color)
   1134 {
   1135   int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
   1136   uint8_t byte = 0;
   1137 
   1138   startWrite();
   1139   for (int16_t j = 0; j < h; j++, y++)
   1140   {
   1141     for (int16_t i = 0; i < w; i++)
   1142     {
   1143       if (i & 7)
   1144       {
   1145         byte <<= 1;
   1146       }
   1147       else
   1148       {
   1149         byte = bitmap[j * byteWidth + i / 8];
   1150       }
   1151       if (byte & 0x80)
   1152       {
   1153         writePixel(x + i, y, color);
   1154       }
   1155     }
   1156   }
   1157   endWrite();
   1158 }
   1159 
   1160 /**************************************************************************/
   1161 /*!
   1162   @brief  Draw a RAM-resident 1-bit image at the specified (x,y) position, using the specified foreground (for set bits) and background (unset bits) colors.
   1163   @param  x       Top left corner x coordinate
   1164   @param  y       Top left corner y coordinate
   1165   @param  bitmap  byte array with monochrome bitmap
   1166   @param  w       Width of bitmap in pixels
   1167   @param  h       Height of bitmap in pixels
   1168   @param  color   16-bit 5-6-5 Color to draw pixels with
   1169   @param  bg      16-bit 5-6-5 Color to draw background with
   1170 */
   1171 /**************************************************************************/
   1172 void Arduino_GFX::drawBitmap(int16_t x, int16_t y,
   1173                              uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg)
   1174 {
   1175   int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
   1176   uint8_t byte = 0;
   1177 
   1178   startWrite();
   1179   for (int16_t j = 0; j < h; j++, y++)
   1180   {
   1181     for (int16_t i = 0; i < w; i++)
   1182     {
   1183       if (i & 7)
   1184       {
   1185         byte <<= 1;
   1186       }
   1187       else
   1188       {
   1189         byte = bitmap[j * byteWidth + i / 8];
   1190       }
   1191       writePixel(x + i, y, (byte & 0x80) ? color : bg);
   1192     }
   1193   }
   1194   endWrite();
   1195 }
   1196 
   1197 /**************************************************************************/
   1198 /*!
   1199    @brief   Draw PROGMEM-resident XBitMap Files (*.xbm), exported from GIMP.
   1200     Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor.
   1201     C Array can be directly used with this function.
   1202     There is no RAM-resident version of this function; if generating bitmaps
   1203     in RAM, use the format defined by drawBitmap() and call that instead.
   1204   @param  x       Top left corner x coordinate
   1205   @param  y       Top left corner y coordinate
   1206   @param  bitmap  byte array with monochrome bitmap
   1207   @param  w       Width of bitmap in pixels
   1208   @param  h       Height of bitmap in pixels
   1209   @param  color   16-bit 5-6-5 Color to draw pixels with
   1210 */
   1211 /**************************************************************************/
   1212 void Arduino_GFX::drawXBitmap(int16_t x, int16_t y,
   1213                               const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color)
   1214 {
   1215   int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
   1216   uint8_t byte = 0;
   1217 
   1218   startWrite();
   1219   for (int16_t j = 0; j < h; j++, y++)
   1220   {
   1221     for (int16_t i = 0; i < w; i++)
   1222     {
   1223       if (i & 7)
   1224       {
   1225         byte >>= 1;
   1226       }
   1227       else
   1228       {
   1229         byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
   1230       }
   1231       // Nearly identical to drawBitmap(), only the bit order
   1232       // is reversed here (left-to-right = LSB to MSB):
   1233       if (byte & 0x01)
   1234       {
   1235         writePixel(x + i, y, color);
   1236       }
   1237     }
   1238   }
   1239   endWrite();
   1240 }
   1241 
   1242 /**************************************************************************/
   1243 /*!
   1244   @brief  Draw a PROGMEM-resident 8-bit image (grayscale) at the specified (x,y) pos.
   1245   @param  x       Top left corner x coordinate
   1246   @param  y       Top left corner y coordinate
   1247   @param  bitmap  byte array with grayscale bitmap
   1248   @param  w       Width of bitmap in pixels
   1249   @param  h       Height of bitmap in pixels
   1250 */
   1251 /**************************************************************************/
   1252 void Arduino_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
   1253                                       const uint8_t bitmap[], int16_t w, int16_t h)
   1254 {
   1255   uint8_t v;
   1256   startWrite();
   1257   for (int16_t j = 0; j < h; j++, y++)
   1258   {
   1259     for (int16_t i = 0; i < w; i++)
   1260     {
   1261       v = (uint8_t)pgm_read_byte(&bitmap[j * w + i]);
   1262       writePixel(x + i, y, color565(v, v, v));
   1263     }
   1264   }
   1265   endWrite();
   1266 }
   1267 
   1268 /**************************************************************************/
   1269 /*!
   1270   @brief  Draw a RAM-resident 8-bit image (grayscale) at the specified (x,y) pos.
   1271   @param  x       Top left corner x coordinate
   1272   @param  y       Top left corner y coordinate
   1273   @param  bitmap  byte array with grayscale bitmap
   1274   @param  w       Width of bitmap in pixels
   1275   @param  h       Height of bitmap in pixels
   1276 */
   1277 /**************************************************************************/
   1278 void Arduino_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
   1279                                       uint8_t *bitmap, int16_t w, int16_t h)
   1280 {
   1281   uint8_t v;
   1282   startWrite();
   1283   for (int16_t j = 0; j < h; j++, y++)
   1284   {
   1285     for (int16_t i = 0; i < w; i++)
   1286     {
   1287       v = bitmap[j * w + i];
   1288       writePixel(x + i, y, color565(v, v, v));
   1289     }
   1290   }
   1291   endWrite();
   1292 }
   1293 
   1294 /**************************************************************************/
   1295 /*!
   1296   @brief  Draw a PROGMEM-resident 8-bit image (grayscale) with a 1-bit mask
   1297     (set bits = opaque, unset bits = clear) at the specified (x,y) position.
   1298     BOTH buffers (grayscale and mask) must be PROGMEM-resident.
   1299   @param  x       Top left corner x coordinate
   1300   @param  y       Top left corner y coordinate
   1301   @param  bitmap  byte array with grayscale bitmap
   1302   @param  mask    byte array with mask bitmap
   1303   @param  w       Width of bitmap in pixels
   1304   @param  h       Height of bitmap in pixels
   1305 */
   1306 /**************************************************************************/
   1307 void Arduino_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
   1308                                       const uint8_t bitmap[], const uint8_t mask[],
   1309                                       int16_t w, int16_t h)
   1310 {
   1311   int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
   1312   uint8_t byte = 0;
   1313   uint8_t v;
   1314   startWrite();
   1315   for (int16_t j = 0; j < h; j++, y++)
   1316   {
   1317     for (int16_t i = 0; i < w; i++)
   1318     {
   1319       if (i & 7)
   1320       {
   1321         byte <<= 1;
   1322       }
   1323       else
   1324       {
   1325         byte = pgm_read_byte(&mask[j * bw + i / 8]);
   1326       }
   1327       if (byte & 0x80)
   1328       {
   1329         v = (uint8_t)pgm_read_byte(&bitmap[j * w + i]);
   1330         writePixel(x + i, y, color565(v, v, v));
   1331       }
   1332     }
   1333   }
   1334   endWrite();
   1335 }
   1336 
   1337 /**************************************************************************/
   1338 /*!
   1339   @brief  Draw a RAM-resident 8-bit image (grayscale) with a 1-bit mask
   1340     (set bits = opaque, unset bits = clear) at the specified (x,y) position.
   1341     BOTH buffers (grayscale and mask) must be RAM-residentt, no mix-and-match
   1342   @param  x       Top left corner x coordinate
   1343   @param  y       Top left corner y coordinate
   1344   @param  bitmap  byte array with grayscale bitmap
   1345   @param  mask    byte array with mask bitmap
   1346   @param  w       Width of bitmap in pixels
   1347   @param  h       Height of bitmap in pixels
   1348 */
   1349 /**************************************************************************/
   1350 void Arduino_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
   1351                                       uint8_t *bitmap, uint8_t *mask, int16_t w, int16_t h)
   1352 {
   1353   int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
   1354   uint8_t byte = 0;
   1355   uint8_t v;
   1356   startWrite();
   1357   for (int16_t j = 0; j < h; j++, y++)
   1358   {
   1359     for (int16_t i = 0; i < w; i++)
   1360     {
   1361       if (i & 7)
   1362       {
   1363         byte <<= 1;
   1364       }
   1365       else
   1366       {
   1367         byte = mask[j * bw + i / 8];
   1368       }
   1369       if (byte & 0x80)
   1370       {
   1371         v = bitmap[j * w + i];
   1372         writePixel(x + i, y, color565(v, v, v));
   1373       }
   1374     }
   1375   }
   1376   endWrite();
   1377 }
   1378 
   1379 /**************************************************************************/
   1380 /*!
   1381   @brief  Draw a Indexed 16-bit image (RGB 5/6/5) at the specified (x,y) position.
   1382   @param  x           Top left corner x coordinate
   1383   @param  y           Top left corner y coordinate
   1384   @param  bitmap      byte array of Indexed color bitmap
   1385   @param  color_index byte array of 16-bit color index
   1386   @param  w           Width of bitmap in pixels
   1387   @param  h           Height of bitmap in pixels
   1388 */
   1389 /**************************************************************************/
   1390 void Arduino_GFX::drawIndexedBitmap(int16_t x, int16_t y,
   1391                                     uint8_t *bitmap, uint16_t *color_index, int16_t w, int16_t h)
   1392 {
   1393   int32_t offset = 0;
   1394   startWrite();
   1395   for (int16_t j = 0; j < h; j++, y++)
   1396   {
   1397     for (int16_t i = 0; i < w; i++)
   1398     {
   1399       writePixel(x + i, y, color_index[bitmap[offset++]]);
   1400     }
   1401   }
   1402   endWrite();
   1403 }
   1404 
   1405 /**************************************************************************/
   1406 /*!
   1407   @brief  Draw a RAM-resident 3-bit image (RGB 1/1/1) at the specified (x,y) position.
   1408   @param  x       Top left corner x coordinate
   1409   @param  y       Top left corner y coordinate
   1410   @param  bitmap  byte array with 3-bit color bitmap
   1411   @param  w       Width of bitmap in pixels
   1412   @param  h       Height of bitmap in pixels
   1413 */
   1414 /**************************************************************************/
   1415 void Arduino_GFX::draw3bitRGBBitmap(int16_t x, int16_t y,
   1416                                     uint8_t *bitmap, int16_t w, int16_t h)
   1417 {
   1418   int32_t offset = 0, idx = 0;
   1419   uint8_t c = 0;
   1420   uint16_t d;
   1421   startWrite();
   1422   for (int16_t j = 0; j < h; j++, y++)
   1423   {
   1424     for (int16_t i = 0; i < w; i++)
   1425     {
   1426       if (offset & 1)
   1427       {
   1428         d = (((c & 0b100) ? RED : 0) |
   1429              ((c & 0b010) ? GREEN : 0) |
   1430              ((c & 0b001) ? BLUE : 0));
   1431       }
   1432       else
   1433       {
   1434         c = bitmap[idx++];
   1435         d = (((c & 0b100000) ? RED : 0) |
   1436              ((c & 0b010000) ? GREEN : 0) |
   1437              ((c & 0b001000) ? BLUE : 0));
   1438       }
   1439       writePixel(x + i, y, d);
   1440       offset++;
   1441     }
   1442   }
   1443   endWrite();
   1444 }
   1445 
   1446 /**************************************************************************/
   1447 /*!
   1448   @brief  Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) position.
   1449   @param  x       Top left corner x coordinate
   1450   @param  y       Top left corner y coordinate
   1451   @param  bitmap  byte array with 16-bit color bitmap
   1452   @param  w       Width of bitmap in pixels
   1453   @param  h       Height of bitmap in pixels
   1454 */
   1455 /**************************************************************************/
   1456 void Arduino_GFX::draw16bitRGBBitmap(int16_t x, int16_t y,
   1457                                      const uint16_t bitmap[], int16_t w, int16_t h)
   1458 {
   1459   int32_t offset = 0;
   1460   startWrite();
   1461   for (int16_t j = 0; j < h; j++, y++)
   1462   {
   1463     for (int16_t i = 0; i < w; i++)
   1464     {
   1465       writePixel(x + i, y, pgm_read_word(&bitmap[offset++]));
   1466     }
   1467   }
   1468   endWrite();
   1469 }
   1470 
   1471 /**************************************************************************/
   1472 /*!
   1473   @brief  Draw a RAM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) position.
   1474   @param  x       Top left corner x coordinate
   1475   @param  y       Top left corner y coordinate
   1476   @param  bitmap  byte array with 16-bit color bitmap
   1477   @param  w       Width of bitmap in pixels
   1478   @param  h       Height of bitmap in pixels
   1479 */
   1480 /**************************************************************************/
   1481 void Arduino_GFX::draw16bitRGBBitmap(int16_t x, int16_t y,
   1482                                      uint16_t *bitmap, int16_t w, int16_t h)
   1483 {
   1484   int32_t offset = 0;
   1485   startWrite();
   1486   for (int16_t j = 0; j < h; j++, y++)
   1487   {
   1488     for (int16_t i = 0; i < w; i++)
   1489     {
   1490       writePixel(x + i, y, bitmap[offset++]);
   1491     }
   1492   }
   1493   endWrite();
   1494 }
   1495 
   1496 /**************************************************************************/
   1497 /*!
   1498   @brief  Draw a RAM-resident 16-bit Big Endian image (RGB 5/6/5) at the specified (x,y) position.
   1499   @param  x       Top left corner x coordinate
   1500   @param  y       Top left corner y coordinate
   1501   @param  bitmap  byte array with 16-bit color bitmap
   1502   @param  w       Width of bitmap in pixels
   1503   @param  h       Height of bitmap in pixels
   1504 */
   1505 /**************************************************************************/
   1506 void Arduino_GFX::draw16bitBeRGBBitmap(int16_t x, int16_t y,
   1507                                        uint16_t *bitmap, int16_t w, int16_t h)
   1508 {
   1509   int32_t offset = 0;
   1510   uint16_t p;
   1511   startWrite();
   1512   for (int16_t j = 0; j < h; j++, y++)
   1513   {
   1514     for (int16_t i = 0; i < w; i++)
   1515     {
   1516       p = bitmap[offset++];
   1517       MSB_16_SET(p, p);
   1518       writePixel(x + i, y, p);
   1519     }
   1520   }
   1521   endWrite();
   1522 }
   1523 
   1524 /**************************************************************************/
   1525 /*!
   1526   @brief  Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask
   1527     (set bits = opaque, unset bits = clear) at the specified (x,y) position.
   1528     BOTH buffers (color and mask) must be PROGMEM-resident.
   1529   @param  x       Top left corner x coordinate
   1530   @param  y       Top left corner y coordinate
   1531   @param  bitmap  byte array with 16-bit color bitmap
   1532   @param  mask    byte array with monochrome mask bitmap
   1533   @param  w       Width of bitmap in pixels
   1534   @param  h       Height of bitmap in pixels
   1535 */
   1536 /**************************************************************************/
   1537 void Arduino_GFX::draw16bitRGBBitmap(int16_t x, int16_t y,
   1538                                      const uint16_t bitmap[], const uint8_t mask[],
   1539                                      int16_t w, int16_t h)
   1540 {
   1541   int32_t offset = 0;
   1542   int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
   1543   uint8_t byte = 0;
   1544   startWrite();
   1545   for (int16_t j = 0; j < h; j++, y++)
   1546   {
   1547     for (int16_t i = 0; i < w; i++)
   1548     {
   1549       if (i & 7)
   1550       {
   1551         byte <<= 1;
   1552       }
   1553       else
   1554       {
   1555         byte = pgm_read_byte(&mask[j * bw + i / 8]);
   1556       }
   1557       if (byte & 0x80)
   1558       {
   1559         writePixel(x + i, y, pgm_read_word(&bitmap[offset]));
   1560       }
   1561       offset++;
   1562     }
   1563   }
   1564   endWrite();
   1565 }
   1566 
   1567 /**************************************************************************/
   1568 /*!
   1569   @brief  Draw a RAM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask
   1570     (set bits = opaque, unset bits = clear) at the specified (x,y) position.
   1571     BOTH buffers (color and mask) must be RAM-resident.
   1572   @param  x       Top left corner x coordinate
   1573   @param  y       Top left corner y coordinate
   1574   @param  bitmap  byte array with 16-bit color bitmap
   1575   @param  mask    byte array with monochrome mask bitmap
   1576   @param  w       Width of bitmap in pixels
   1577   @param  h       Height of bitmap in pixels
   1578 */
   1579 /**************************************************************************/
   1580 void Arduino_GFX::draw16bitRGBBitmap(int16_t x, int16_t y,
   1581                                      uint16_t *bitmap, uint8_t *mask, int16_t w, int16_t h)
   1582 {
   1583   int32_t offset = 0, maskIdx = 0;
   1584   uint8_t byte = 0;
   1585   startWrite();
   1586   for (int16_t j = 0; j < h; j++, y++)
   1587   {
   1588     for (int16_t i = 0; i < w; i++)
   1589     {
   1590       if (i & 7)
   1591       {
   1592         byte <<= 1;
   1593       }
   1594       else
   1595       {
   1596         byte = mask[maskIdx++];
   1597       }
   1598       if (byte & 0x80)
   1599       {
   1600         writePixel(x + i, y, bitmap[offset]);
   1601       }
   1602       offset++;
   1603     }
   1604   }
   1605   endWrite();
   1606 }
   1607 
   1608 /**************************************************************************/
   1609 /*!
   1610   @brief  Draw a PROGMEM-resident 24-bit image (RGB 5/6/5) at the specified (x,y) position.
   1611   @param  x       Top left corner x coordinate
   1612   @param  y       Top left corner y coordinate
   1613   @param  bitmap  byte array with 16-bit color bitmap
   1614   @param  w       Width of bitmap in pixels
   1615   @param  h       Height of bitmap in pixels
   1616 */
   1617 /**************************************************************************/
   1618 void Arduino_GFX::draw24bitRGBBitmap(int16_t x, int16_t y,
   1619                                      const uint8_t bitmap[], int16_t w, int16_t h)
   1620 {
   1621   int32_t offset = 0;
   1622   startWrite();
   1623   for (int16_t j = 0; j < h; j++, y++)
   1624   {
   1625     for (int16_t i = 0; i < w; i++)
   1626     {
   1627       writePixel(x + i, y, color565(pgm_read_byte(&bitmap[offset]), pgm_read_byte(&bitmap[offset + 1]), pgm_read_byte(&bitmap[offset + 2])));
   1628       offset += 3;
   1629     }
   1630   }
   1631   endWrite();
   1632 }
   1633 
   1634 /**************************************************************************/
   1635 /*!
   1636   @brief  Draw a RAM-resident 24-bit image (RGB 5/6/5) at the specified (x,y) position.
   1637   @param  x       Top left corner x coordinate
   1638   @param  y       Top left corner y coordinate
   1639   @param  bitmap  byte array with 16-bit color bitmap
   1640   @param  w       Width of bitmap in pixels
   1641   @param  h       Height of bitmap in pixels
   1642 */
   1643 /**************************************************************************/
   1644 void Arduino_GFX::draw24bitRGBBitmap(int16_t x, int16_t y,
   1645                                      uint8_t *bitmap, int16_t w, int16_t h)
   1646 {
   1647   int32_t offset = 0;
   1648   startWrite();
   1649   for (int16_t j = 0; j < h; j++, y++)
   1650   {
   1651     for (int16_t i = 0; i < w; i++)
   1652     {
   1653       writePixel(x + i, y, color565(bitmap[offset], bitmap[offset + 1], bitmap[offset + 2]));
   1654       offset += 3;
   1655     }
   1656   }
   1657   endWrite();
   1658 }
   1659 
   1660 /**************************************************************************/
   1661 /*!
   1662   @brief  Draw a PROGMEM-resident 24-bit image (RGB 5/6/5) with a 1-bit mask
   1663     (set bits = opaque, unset bits = clear) at the specified (x,y) position.
   1664     BOTH buffers (color and mask) must be PROGMEM-resident.
   1665   @param  x       Top left corner x coordinate
   1666   @param  y       Top left corner y coordinate
   1667   @param  bitmap  byte array with 16-bit color bitmap
   1668   @param  mask    byte array with monochrome mask bitmap
   1669   @param  w       Width of bitmap in pixels
   1670   @param  h       Height of bitmap in pixels
   1671 */
   1672 /**************************************************************************/
   1673 void Arduino_GFX::draw24bitRGBBitmap(int16_t x, int16_t y,
   1674                                      const uint8_t bitmap[], const uint8_t mask[],
   1675                                      int16_t w, int16_t h)
   1676 {
   1677   int32_t offset = 0;
   1678   int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
   1679   uint8_t byte = 0;
   1680   startWrite();
   1681   for (int16_t j = 0; j < h; j++, y++)
   1682   {
   1683     for (int16_t i = 0; i < w; i++)
   1684     {
   1685       if (i & 7)
   1686       {
   1687         byte <<= 1;
   1688       }
   1689       else
   1690       {
   1691         byte = pgm_read_byte(&mask[j * bw + i / 8]);
   1692       }
   1693       if (byte & 0x80)
   1694       {
   1695         writePixel(x + i, y, color565(pgm_read_byte(&bitmap[offset]), pgm_read_byte(&bitmap[offset + 1]), pgm_read_byte(&bitmap[offset + 2])));
   1696       }
   1697       offset += 3;
   1698     }
   1699   }
   1700   endWrite();
   1701 }
   1702 
   1703 /**************************************************************************/
   1704 /*!
   1705   @brief  Draw a RAM-resident 24-bit image (RGB 5/6/5) with a 1-bit mask
   1706     (set bits = opaque, unset bits = clear) at the specified (x,y) position.
   1707     BOTH buffers (color and mask) must be RAM-resident.
   1708   @param  x       Top left corner x coordinate
   1709   @param  y       Top left corner y coordinate
   1710   @param  bitmap  byte array with 16-bit color bitmap
   1711   @param  mask    byte array with monochrome mask bitmap
   1712   @param  w       Width of bitmap in pixels
   1713   @param  h       Height of bitmap in pixels
   1714 */
   1715 /**************************************************************************/
   1716 void Arduino_GFX::draw24bitRGBBitmap(int16_t x, int16_t y,
   1717                                      uint8_t *bitmap, uint8_t *mask, int16_t w, int16_t h)
   1718 {
   1719   int32_t offset = 0;
   1720   int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
   1721   uint8_t byte = 0;
   1722   startWrite();
   1723   for (int16_t j = 0; j < h; j++, y++)
   1724   {
   1725     for (int16_t i = 0; i < w; i++)
   1726     {
   1727       if (i & 7)
   1728       {
   1729         byte <<= 1;
   1730       }
   1731       else
   1732       {
   1733         byte = mask[j * bw + i / 8];
   1734       }
   1735       if (byte & 0x80)
   1736       {
   1737         writePixel(x + i, y, color565(bitmap[offset], bitmap[offset + 1], bitmap[offset + 2]));
   1738       }
   1739       offset += 3;
   1740     }
   1741   }
   1742   endWrite();
   1743 }
   1744 
   1745 #if defined(U8G2_FONT_SUPPORT)
   1746 uint16_t Arduino_GFX::u8g2_font_get_word(const uint8_t *font, uint8_t offset)
   1747 {
   1748   uint16_t pos;
   1749   font += offset;
   1750   pos = pgm_read_byte(font);
   1751   font++;
   1752   pos <<= 8;
   1753   pos += pgm_read_byte(font);
   1754 
   1755   return pos;
   1756 }
   1757 
   1758 uint8_t Arduino_GFX::u8g2_font_decode_get_unsigned_bits(uint8_t cnt)
   1759 {
   1760   uint8_t val;
   1761   uint8_t bit_pos = _u8g2_decode_bit_pos;
   1762   uint8_t bit_pos_plus_cnt;
   1763 
   1764   val = pgm_read_byte(_u8g2_decode_ptr);
   1765 
   1766   val >>= bit_pos;
   1767   bit_pos_plus_cnt = bit_pos;
   1768   bit_pos_plus_cnt += cnt;
   1769   if (bit_pos_plus_cnt >= 8)
   1770   {
   1771     uint8_t s = 8;
   1772     s -= bit_pos;
   1773     _u8g2_decode_ptr++;
   1774     val |= pgm_read_byte(_u8g2_decode_ptr) << (s);
   1775     bit_pos_plus_cnt -= 8;
   1776   }
   1777   val &= (1U << cnt) - 1;
   1778 
   1779   _u8g2_decode_bit_pos = bit_pos_plus_cnt;
   1780 
   1781   return val;
   1782 }
   1783 
   1784 int8_t Arduino_GFX::u8g2_font_decode_get_signed_bits(uint8_t cnt)
   1785 {
   1786   int8_t v, d;
   1787   v = (int8_t)u8g2_font_decode_get_unsigned_bits(cnt);
   1788   d = 1;
   1789   cnt--;
   1790   d <<= cnt;
   1791   v -= d;
   1792 
   1793   return v;
   1794 }
   1795 
   1796 void Arduino_GFX::u8g2_font_decode_len(uint8_t len, uint8_t is_foreground, uint16_t color, uint16_t bg)
   1797 {
   1798   uint8_t cnt;     /* total number of remaining pixels, which have to be drawn */
   1799   uint8_t rem;     /* remaining pixel to the right edge of the glyph */
   1800   uint8_t current; /* number of pixels, which need to be drawn for the draw procedure */
   1801   /* current is either equal to cnt or equal to rem */
   1802 
   1803   /* target position on the screen */
   1804   uint16_t x, y;
   1805 
   1806   cnt = len;
   1807 
   1808   /* get the local position */
   1809   uint8_t lx = _u8g2_dx;
   1810   uint8_t ly = _u8g2_dy;
   1811 
   1812   for (;;)
   1813   {
   1814     /* calculate the number of pixel to the right edge of the glyph */
   1815     rem = _u8g2_char_width;
   1816     rem -= lx;
   1817 
   1818     /* calculate how many pixel to draw. This is either to the right edge */
   1819     /* or lesser, if not enough pixel are left */
   1820     current = rem;
   1821     if (cnt < rem)
   1822       current = cnt;
   1823 
   1824     /* now draw the line, but apply the rotation around the glyph target position */
   1825     // u8g2_font_decode_draw_pixel(u8g2, lx,ly,current, is_foreground);
   1826 
   1827     if (textsize_x == 1 && textsize_y == 1)
   1828     {
   1829       /* get target position */
   1830       x = _u8g2_target_x + lx;
   1831       y = _u8g2_target_y + ly;
   1832 
   1833       /* draw foreground and background (if required) */
   1834       if (is_foreground)
   1835       {
   1836         writeFastHLine(x, y, current, color);
   1837       }
   1838       else if (bg != color)
   1839       {
   1840         writeFastHLine(x, y, current, bg);
   1841       }
   1842     }
   1843     else
   1844     {
   1845       /* get target position */
   1846       x = _u8g2_target_x + (lx * textsize_x);
   1847       y = _u8g2_target_y + (ly * textsize_y);
   1848 
   1849       /* draw foreground and background (if required) */
   1850       if (is_foreground)
   1851       {
   1852         writeFillRect(x, y, (current * textsize_x) - text_pixel_margin,
   1853                       textsize_y - text_pixel_margin, color);
   1854       }
   1855       else if (bg != color)
   1856       {
   1857         writeFillRect(x, y, (current * textsize_x) - text_pixel_margin,
   1858                       textsize_y - text_pixel_margin, bg);
   1859       }
   1860     }
   1861 
   1862     /* check, whether the end of the run length code has been reached */
   1863     if (cnt < rem)
   1864       break;
   1865     cnt -= rem;
   1866     lx = 0;
   1867     ly++;
   1868   }
   1869   lx += cnt;
   1870 
   1871   _u8g2_dx = lx;
   1872   _u8g2_dy = ly;
   1873 }
   1874 #endif // defined(U8G2_FONT_SUPPORT)
   1875 
   1876 // TEXT- AND CHARACTER-HANDLING FUNCTIONS ----------------------------------
   1877 
   1878 // Draw a character
   1879 /**************************************************************************/
   1880 /*!
   1881   @brief  Draw a single character
   1882   @param  x       Bottom left corner x coordinate
   1883   @param  y       Bottom left corner y coordinate
   1884   @param  c       The 8-bit font-indexed character (likely ascii)
   1885   @param  color   16-bit 5-6-5 Color to draw chraracter with
   1886   @param  bg      16-bit 5-6-5 Color to fill background with (if same as color, no background)
   1887 */
   1888 /**************************************************************************/
   1889 void Arduino_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
   1890                            uint16_t color, uint16_t bg)
   1891 {
   1892   int16_t block_w;
   1893   int16_t block_h;
   1894 
   1895 #if !defined(ATTINY_CORE)
   1896   if (gfxFont) // custom font
   1897   {
   1898     // Character is assumed previously filtered by write() to eliminate
   1899     // newlines, returns, non-printable characters, etc.  Calling
   1900     // drawChar() directly with 'bad' characters of font may cause mayhem!
   1901 
   1902     c -= (uint8_t)pgm_read_byte(&gfxFont->first);
   1903     GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c);
   1904     uint8_t *bitmap = pgm_read_bitmap_ptr(gfxFont);
   1905 
   1906     uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
   1907     uint8_t w = pgm_read_byte(&glyph->width),
   1908             h = pgm_read_byte(&glyph->height),
   1909             xAdvance = pgm_read_byte(&glyph->xAdvance),
   1910             yAdvance = pgm_read_byte(&gfxFont->yAdvance),
   1911             baseline = yAdvance * 2 / 3; // TODO: baseline is an arbitrary currently, may be define in font file
   1912     int8_t xo = pgm_read_byte(&glyph->xOffset),
   1913            yo = pgm_read_byte(&glyph->yOffset);
   1914     uint8_t xx, yy, bits = 0, bit = 0;
   1915     int16_t xo16 = xo, yo16 = yo;
   1916 
   1917     if (xAdvance < w)
   1918     {
   1919       xAdvance = w; // Don't know why it exists
   1920     }
   1921 
   1922     block_w = xAdvance * textsize_x;
   1923     block_h = yAdvance * textsize_y;
   1924     if (
   1925         (x > _max_x) ||            // Clip right
   1926         (y > _max_y) ||            // Clip bottom
   1927         ((x + block_w - 1) < 0) || // Clip left
   1928         ((y + block_h - 1) < 0)    // Clip top
   1929     )
   1930     {
   1931       return;
   1932     }
   1933 
   1934     // NOTE: Different from Adafruit_GFX design, Adruino_GFX also cater background.
   1935     // Since it may introduce many ugly output, it should limited using on mono font only.
   1936     startWrite();
   1937     if (bg != color) // have background color
   1938     {
   1939       writeFillRect(x, y - (baseline * textsize_y), block_w, block_h, bg);
   1940     }
   1941     for (yy = 0; yy < h; yy++)
   1942     {
   1943       for (xx = 0; xx < w; xx++)
   1944       {
   1945         if (!(bit++ & 7))
   1946         {
   1947           bits = pgm_read_byte(&bitmap[bo++]);
   1948         }
   1949         if (bits & 0x80)
   1950         {
   1951           if (textsize_x == 1 && textsize_y == 1)
   1952           {
   1953             writePixel(x + xo + xx, y + yo + yy, color);
   1954           }
   1955           else
   1956           {
   1957             writeFillRect(x + (xo16 + xx) * textsize_x, y + (yo16 + yy) * textsize_y,
   1958                           textsize_x - text_pixel_margin, textsize_y - text_pixel_margin, color);
   1959           }
   1960         }
   1961         bits <<= 1;
   1962       }
   1963     }
   1964     endWrite();
   1965   }
   1966   else // 'Classic' built-in font
   1967 #endif // !defined(ATTINY_CORE)
   1968 #if defined(U8G2_FONT_SUPPORT)
   1969       if (u8g2Font)
   1970   {
   1971     if ((_u8g2_decode_ptr) && (_u8g2_char_width > 0))
   1972     {
   1973       uint8_t a, b;
   1974 
   1975       _u8g2_target_x = x + (_u8g2_char_x * textsize_x);
   1976       _u8g2_target_y = y - ((_u8g2_char_height + _u8g2_char_y) * textsize_y);
   1977       // log_d("_u8g2_target_x: %d, _u8g2_target_y: %d", _u8g2_target_x, _u8g2_target_y);
   1978 
   1979       /* reset local x/y position */
   1980       _u8g2_dx = 0;
   1981       _u8g2_dy = 0;
   1982       /* decode glyph */
   1983       startWrite();
   1984       for (;;)
   1985       {
   1986         a = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_0);
   1987         b = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_1);
   1988         // log_d("a: %d, b: %d", a, b);
   1989         do
   1990         {
   1991           u8g2_font_decode_len(a, 0, color, bg);
   1992           u8g2_font_decode_len(b, 1, color, bg);
   1993         } while (u8g2_font_decode_get_unsigned_bits(1) != 0);
   1994 
   1995         if (_u8g2_dy >= _u8g2_char_height)
   1996           break;
   1997       }
   1998       endWrite();
   1999     }
   2000   }
   2001   else // glcdfont
   2002 #endif // defined(U8G2_FONT_SUPPORT)
   2003   {
   2004     block_w = 6 * textsize_x;
   2005     block_h = 8 * textsize_y;
   2006     if (
   2007         (x > _max_x) ||            // Clip right
   2008         (y > _max_y) ||            // Clip bottom
   2009         ((x + block_w - 1) < 0) || // Clip left
   2010         ((y + block_h - 1) < 0)    // Clip top
   2011     )
   2012     {
   2013       return;
   2014     }
   2015 
   2016     startWrite();
   2017     for (int8_t i = 0; i < 5; i++)
   2018     { // Char bitmap = 5 columns
   2019       uint8_t line = pgm_read_byte(&font[c * 5 + i]);
   2020       for (int8_t j = 0; j < 8; j++, line >>= 1)
   2021       {
   2022         if (line & 1)
   2023         {
   2024           if (textsize_x == 1 && textsize_y == 1)
   2025           {
   2026             writePixel(x + i, y + j, color);
   2027           }
   2028           else
   2029           {
   2030             if (text_pixel_margin > 0)
   2031             {
   2032               writeFillRect(x + (i * textsize_x), y + j * textsize_y, textsize_x - text_pixel_margin, textsize_y - text_pixel_margin, color);
   2033               writeFillRect(x + ((i + 1) * textsize_x) - text_pixel_margin, y + j * textsize_y, text_pixel_margin, textsize_y, bg);
   2034               writeFillRect(x + (i * textsize_x), y + ((j + 1) * textsize_y) - text_pixel_margin, textsize_x - text_pixel_margin, text_pixel_margin, bg);
   2035             }
   2036             else
   2037             {
   2038               writeFillRect(x + i * textsize_x, y + j * textsize_y, textsize_x, textsize_y, color);
   2039             }
   2040           }
   2041         }
   2042         else if (bg != color)
   2043         {
   2044           if (textsize_x == 1 && textsize_y == 1)
   2045           {
   2046             writePixel(x + i, y + j, bg);
   2047           }
   2048           else
   2049           {
   2050             writeFillRect(x + i * textsize_x, y + j * textsize_y, textsize_x, textsize_y, bg);
   2051           }
   2052         }
   2053       }
   2054     }
   2055     if (bg != color)
   2056     { // If opaque, draw vertical line for last column
   2057       if (textsize_x == 1 && textsize_y == 1)
   2058       {
   2059         writeFastVLine(x + 5, y, 8, bg);
   2060       }
   2061       else
   2062       {
   2063         writeFillRect(x + 5 * textsize_x, y, textsize_x, 8 * textsize_y, bg);
   2064       }
   2065     }
   2066     endWrite();
   2067   }
   2068 }
   2069 
   2070 /**************************************************************************/
   2071 /*!
   2072   @brief  Print one byte/character of data, used to support print()
   2073   @param  c   The 8-bit ascii character to write
   2074 */
   2075 /**************************************************************************/
   2076 size_t Arduino_GFX::write(uint8_t c)
   2077 {
   2078 #if !defined(ATTINY_CORE)
   2079   if (gfxFont) // custom font
   2080   {
   2081     if (c == '\n') // Newline
   2082     {
   2083       cursor_x = 0; // Reset x to zero, advance y by one line
   2084       cursor_y += (int16_t)textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
   2085     }
   2086     else if (c != '\r') // Not a carriage return; is normal char
   2087     {
   2088       uint8_t first = pgm_read_byte(&gfxFont->first),
   2089               last = pgm_read_byte(&gfxFont->last);
   2090       if ((c >= first) && (c <= last)) // Char present in this font?
   2091       {
   2092         GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first);
   2093         uint8_t gw = pgm_read_byte(&glyph->width),
   2094                 xa = pgm_read_byte(&glyph->xAdvance);
   2095         int16_t xo = pgm_read_byte(&glyph->xOffset);
   2096         if (wrap && ((cursor_x + ((xo + gw) * textsize_x) - 1) > _max_x))
   2097         {
   2098           cursor_x = 0; // Reset x to zero, advance y by one line
   2099           cursor_y += (int16_t)textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
   2100         }
   2101         drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor);
   2102         cursor_x += (int16_t)textsize_x * xa;
   2103       }
   2104     }
   2105   }
   2106   else // not gfxFont
   2107 #endif // !defined(ATTINY_CORE)
   2108 #if defined(U8G2_FONT_SUPPORT)
   2109       if (u8g2Font)
   2110   {
   2111     _u8g2_decode_ptr = 0;
   2112 
   2113     if (_enableUTF8Print)
   2114     {
   2115       if (_utf8_state == 0)
   2116       {
   2117         if (c >= 0xfc) /* 6 byte sequence */
   2118         {
   2119           _utf8_state = 5;
   2120           c &= 1;
   2121         }
   2122         else if (c >= 0xf8)
   2123         {
   2124           _utf8_state = 4;
   2125           c &= 3;
   2126         }
   2127         else if (c >= 0xf0)
   2128         {
   2129           _utf8_state = 3;
   2130           c &= 7;
   2131         }
   2132         else if (c >= 0xe0)
   2133         {
   2134           _utf8_state = 2;
   2135           c &= 15;
   2136         }
   2137         else if (c >= 0xc0)
   2138         {
   2139           _utf8_state = 1;
   2140           c &= 0x01f;
   2141         }
   2142         _encoding = c;
   2143       }
   2144       else
   2145       {
   2146         _utf8_state--;
   2147         /* The case b < 0x080 (an illegal UTF8 encoding) is not checked here. */
   2148         _encoding <<= 6;
   2149         c &= 0x03f;
   2150         _encoding |= c;
   2151       }
   2152     } // _enableUTF8Print
   2153     else
   2154     {
   2155       _encoding = c;
   2156     }
   2157 
   2158     if (_utf8_state == 0)
   2159     {
   2160       if (_encoding == '\n')
   2161       {
   2162         cursor_x = 0;
   2163         cursor_y += (int16_t)textsize_y * _u8g2_max_char_height;
   2164       }
   2165       else if (_encoding != '\r')
   2166       { // Ignore carriage returns
   2167         uint8_t *font = u8g2Font;
   2168         const uint8_t *glyph_data = 0;
   2169 
   2170         // extract from u8g2_font_get_glyph_data()
   2171         font += 23; // U8G2_FONT_DATA_STRUCT_SIZE
   2172         if (_encoding <= 255)
   2173         {
   2174           if (_encoding >= 'a')
   2175           {
   2176             font += _u8g2_start_pos_lower_a;
   2177           }
   2178           else if (_encoding >= 'A')
   2179           {
   2180             font += _u8g2_start_pos_upper_A;
   2181           }
   2182 
   2183           for (;;)
   2184           {
   2185             if (pgm_read_byte(font + 1) == 0)
   2186               break;
   2187             if (pgm_read_byte(font) == _encoding)
   2188             {
   2189               glyph_data = font + 2; /* skip encoding and glyph size */
   2190             }
   2191             font += pgm_read_byte(font + 1);
   2192           }
   2193         }
   2194 #ifdef U8G2_WITH_UNICODE
   2195         else
   2196         {
   2197           uint16_t e;
   2198           font += _u8g2_start_pos_unicode;
   2199           const uint8_t *unicode_lookup_table = font;
   2200 
   2201           /* issue 596: search for the glyph start in the unicode lookup table */
   2202           do
   2203           {
   2204             font += u8g2_font_get_word(unicode_lookup_table, 0);
   2205             e = u8g2_font_get_word(unicode_lookup_table, 2);
   2206             unicode_lookup_table += 4;
   2207           } while (e < _encoding);
   2208 
   2209           for (;;)
   2210           {
   2211             e = u8g2_font_get_word(font, 0);
   2212 
   2213             if (e == 0)
   2214               break;
   2215 
   2216             if (e == _encoding)
   2217             {
   2218               glyph_data = font + 3; /* skip encoding and glyph size */
   2219               break;
   2220             }
   2221             font += pgm_read_byte(font + 2);
   2222           }
   2223         }
   2224 #endif
   2225 
   2226         if (glyph_data)
   2227         {
   2228           // u8g2_font_decode_glyph
   2229           _u8g2_decode_ptr = glyph_data;
   2230           _u8g2_decode_bit_pos = 0;
   2231 
   2232           _u8g2_char_width = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_char_width);
   2233           _u8g2_char_height = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_char_height);
   2234           _u8g2_char_x = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_char_x);
   2235           _u8g2_char_y = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_char_y);
   2236           _u8g2_delta_x = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_delta_x);
   2237           // log_d("c: %c, _encoding: %d, _u8g2_char_width: %d, _u8g2_char_height: %d, _u8g2_char_x: %d, _u8g2_char_y: %d, _u8g2_delta_x: %d",
   2238           //       c, _encoding, _u8g2_char_width, _u8g2_char_height, _u8g2_char_x, _u8g2_char_y, _u8g2_delta_x);
   2239 
   2240           if (_u8g2_char_width > 0)
   2241           {
   2242             if (wrap && ((cursor_x + (textsize_x * _u8g2_char_width) - 1) > _max_x))
   2243             {
   2244               cursor_x = 0;
   2245               cursor_y += (int16_t)textsize_y * _u8g2_max_char_height;
   2246             }
   2247           }
   2248 
   2249           drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor);
   2250           cursor_x += (int16_t)textsize_x * _u8g2_delta_x;
   2251         }
   2252       }
   2253     }
   2254   }
   2255   else // glcdfont
   2256 #endif // defined(U8G2_FONT_SUPPORT)
   2257   {
   2258     if (c == '\n')
   2259     {                             // Newline?
   2260       cursor_x = 0;               // Reset x to zero,
   2261       cursor_y += textsize_y * 8; // advance y one line
   2262     }
   2263     else if (c != '\r') // Normal char; ignore carriage returns
   2264     {
   2265       if (wrap && ((cursor_x + (textsize_x * 6) - 1) > _max_x)) // Off right?
   2266       {
   2267         cursor_x = 0;               // Reset x to zero,
   2268         cursor_y += textsize_y * 8; // advance y one line
   2269       }
   2270       drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor);
   2271       cursor_x += textsize_x * 6; // Advance x one char
   2272     }
   2273   }
   2274   return 1;
   2275 }
   2276 
   2277 /**************************************************************************/
   2278 /*!
   2279   @brief  Set text 'magnification' size. Each increase in s makes 1 pixel that much bigger.
   2280   @param  s   Desired text size. 1 is default 6x8, 2 is 12x16, 3 is 18x24, etc
   2281 */
   2282 /**************************************************************************/
   2283 void Arduino_GFX::setTextSize(uint8_t s)
   2284 {
   2285   setTextSize(s, s, 0);
   2286 }
   2287 
   2288 /**************************************************************************/
   2289 /*!
   2290   @brief  Set text 'magnification' size. Each increase in s makes 1 pixel that much bigger.
   2291   @param  s_x Desired text width magnification level in X-axis. 1 is default
   2292   @param  s_y Desired text width magnification level in Y-axis. 1 is default
   2293 */
   2294 /**************************************************************************/
   2295 void Arduino_GFX::setTextSize(uint8_t s_x, uint8_t s_y)
   2296 {
   2297   setTextSize(s_x, s_y, 0);
   2298 }
   2299 
   2300 /**************************************************************************/
   2301 /*!
   2302   @brief  Set text 'magnification' size. Each increase in s makes 1 pixel that much bigger.
   2303   @param  s_x             Desired text width magnification level in X-axis. 1 is default
   2304   @param  s_y             Desired text width magnification level in Y-axis. 1 is default
   2305   @param  pixel_margin    Margin for each text pixel. 0 is default
   2306 */
   2307 /**************************************************************************/
   2308 void Arduino_GFX::setTextSize(uint8_t s_x, uint8_t s_y, uint8_t pixel_margin)
   2309 {
   2310   text_pixel_margin = ((pixel_margin < s_x) && (pixel_margin < s_y)) ? pixel_margin : 0;
   2311   textsize_x = (s_x > 0) ? s_x : 1;
   2312   textsize_y = (s_y > 0) ? s_y : 1;
   2313 }
   2314 
   2315 /**************************************************************************/
   2316 /*!
   2317   @brief  Set rotation setting for display
   2318   @param  r   0 thru 3 corresponding to 4 cardinal rotations
   2319 */
   2320 /**************************************************************************/
   2321 void Arduino_GFX::setRotation(uint8_t r)
   2322 {
   2323   _rotation = (r & 7);
   2324   switch (_rotation)
   2325   {
   2326   case 7:
   2327   case 5:
   2328   case 3:
   2329   case 1:
   2330     _width = HEIGHT;
   2331     _height = WIDTH;
   2332     _max_x = _width - 1;  ///< x zero base bound
   2333     _max_y = _height - 1; ///< y zero base bound
   2334     break;
   2335   case 6:
   2336   case 4:
   2337   case 2:
   2338   default: // case 0:
   2339     _width = WIDTH;
   2340     _height = HEIGHT;
   2341     _max_x = _width - 1;  ///< x zero base bound
   2342     _max_y = _height - 1; ///< y zero base bound
   2343     break;
   2344   }
   2345 }
   2346 
   2347 #if !defined(ATTINY_CORE)
   2348 /**************************************************************************/
   2349 /*!
   2350   @brief  Set the font to display when print()ing, either custom or default
   2351   @param  f   The GFXfont object, if NULL use built in 6x8 font
   2352 */
   2353 /**************************************************************************/
   2354 void Arduino_GFX::setFont(const GFXfont *f)
   2355 {
   2356   gfxFont = (GFXfont *)f;
   2357 #if defined(U8G2_FONT_SUPPORT)
   2358   u8g2Font = NULL;
   2359 #endif // defined(U8G2_FONT_SUPPORT)
   2360 }
   2361 
   2362 /**************************************************************************/
   2363 /*!
   2364   @brief  flush framebuffer to output (for Canvas or NeoPixel sub-class)
   2365 */
   2366 /**************************************************************************/
   2367 void Arduino_GFX::flush()
   2368 {
   2369 }
   2370 #endif // !defined(ATTINY_CORE)
   2371 
   2372 #if defined(U8G2_FONT_SUPPORT)
   2373 void Arduino_GFX::setFont(const uint8_t *font)
   2374 {
   2375   gfxFont = NULL;
   2376   u8g2Font = (uint8_t *)font;
   2377 
   2378   // extract from u8g2_read_font_info()
   2379   /* offset 0 */
   2380   _u8g2_glyph_cnt = pgm_read_byte(font);
   2381   // uint8_t bbx_mode = pgm_read_byte(font + 1);
   2382   _u8g2_bits_per_0 = pgm_read_byte(font + 2);
   2383   _u8g2_bits_per_1 = pgm_read_byte(font + 3);
   2384   // log_d("_u8g2_glyph_cnt: %d, bbx_mode: %d, _u8g2_bits_per_0: %d, _u8g2_bits_per_1: %d",
   2385   //       _u8g2_glyph_cnt, bbx_mode, _u8g2_bits_per_0, _u8g2_bits_per_1);
   2386 
   2387   /* offset 4 */
   2388   _u8g2_bits_per_char_width = pgm_read_byte(font + 4);
   2389   _u8g2_bits_per_char_height = pgm_read_byte(font + 5);
   2390   _u8g2_bits_per_char_x = pgm_read_byte(font + 6);
   2391   _u8g2_bits_per_char_y = pgm_read_byte(font + 7);
   2392   _u8g2_bits_per_delta_x = pgm_read_byte(font + 8);
   2393   // log_d("_u8g2_bits_per_char_width: %d, _u8g2_bits_per_char_height: %d, _u8g2_bits_per_char_x: %d, _u8g2_bits_per_char_y: %d, _u8g2_bits_per_delta_x: %d",
   2394   //       _u8g2_bits_per_char_width, _u8g2_bits_per_char_height, _u8g2_bits_per_char_x, _u8g2_bits_per_char_y, _u8g2_bits_per_delta_x);
   2395 
   2396   /* offset 9 */
   2397   _u8g2_max_char_width = pgm_read_byte(font + 9);
   2398   _u8g2_max_char_height = pgm_read_byte(font + 10);
   2399   // int8_t x_offset = pgm_read_byte(font + 11);
   2400   // int8_t y_offset = pgm_read_byte(font + 12);
   2401   // log_d("_u8g2_max_char_width: %d, _u8g2_max_char_height: %d, x_offset: %d, y_offset: %d",
   2402   //       _u8g2_max_char_width, _u8g2_max_char_height, x_offset, y_offset);
   2403 
   2404   /* offset 13 */
   2405   // int8_t ascent_A = pgm_read_byte(font + 13);
   2406   // int8_t descent_g = pgm_read_byte(font + 14);
   2407   // int8_t ascent_para = pgm_read_byte(font + 15);
   2408   // int8_t descent_para = pgm_read_byte(font + 16);
   2409   // log_d("ascent_A: %d, descent_g: %d, ascent_para: %d, descent_para: %d",
   2410   //       ascent_A, descent_g, ascent_para, descent_para);
   2411 
   2412   /* offset 17 */
   2413   _u8g2_start_pos_upper_A = u8g2_font_get_word(font, 17);
   2414   _u8g2_start_pos_lower_a = u8g2_font_get_word(font, 19);
   2415 #ifdef U8G2_WITH_UNICODE
   2416   _u8g2_start_pos_unicode = u8g2_font_get_word(font, 21);
   2417 #endif
   2418   _u8g2_first_char = pgm_read_byte(font + 23);
   2419   // log_d("_u8g2_start_pos_upper_A: %d, _u8g2_start_pos_lower_a: %d, _u8g2_start_pos_unicode: %d, _u8g2_first_char: %d",
   2420   //       _u8g2_start_pos_upper_A, _u8g2_start_pos_lower_a, _u8g2_start_pos_unicode, _u8g2_first_char);
   2421 }
   2422 
   2423 void Arduino_GFX::setUTF8Print(bool isEnable)
   2424 {
   2425   _enableUTF8Print = isEnable;
   2426 }
   2427 #endif // defined(U8G2_FONT_SUPPORT)
   2428 
   2429 /**************************************************************************/
   2430 /*!
   2431   @brief  Helper to determine size of a character with current font/size.
   2432     Broke this out as it's used by both the PROGMEM- and RAM-resident getTextBounds() functions.
   2433   @param  c       The ascii character in question
   2434   @param  x       Pointer to x location of character
   2435   @param  y       Pointer to y location of character
   2436   @param  minx    Minimum clipping value for X
   2437   @param  miny    Minimum clipping value for Y
   2438   @param  maxx    Maximum clipping value for X
   2439   @param  maxy    Maximum clipping value for Y
   2440 */
   2441 /**************************************************************************/
   2442 void Arduino_GFX::charBounds(char c, int16_t *x, int16_t *y,
   2443                              int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy)
   2444 {
   2445 #if !defined(ATTINY_CORE)
   2446   if (gfxFont) // custom font
   2447   {
   2448     if (c == '\n') // Newline
   2449     {
   2450       *x = 0; // Reset x to zero, advance y by one line
   2451       *y += (int16_t)textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
   2452     }
   2453     else if (c != '\r') // Not a carriage return; is normal char
   2454     {
   2455       uint8_t first = pgm_read_byte(&gfxFont->first),
   2456               last = pgm_read_byte(&gfxFont->last);
   2457       if ((c >= first) && (c <= last)) // Char present in this font?
   2458       {
   2459         GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first);
   2460         uint8_t gw = pgm_read_byte(&glyph->width),
   2461                 gh = pgm_read_byte(&glyph->height),
   2462                 xa = pgm_read_byte(&glyph->xAdvance);
   2463         int16_t xo = pgm_read_byte(&glyph->xOffset),
   2464                 yo = pgm_read_byte(&glyph->yOffset);
   2465         if (wrap && ((*x + ((xo + gw) * textsize_x) - 1) > _max_x))
   2466         {
   2467           *x = 0; // Reset x to zero, advance y by one line
   2468           *y += (int16_t)textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
   2469         }
   2470         int16_t x1 = *x + xo * textsize_x,
   2471                 y1 = *y + yo * textsize_y,
   2472                 x2 = x1 + ((int16_t)gw * textsize_x) - 1,
   2473                 y2 = y1 + ((int16_t)gh * textsize_y) - 1;
   2474         if (x1 < *minx)
   2475         {
   2476           *minx = x1;
   2477         }
   2478         if (y1 < *miny)
   2479         {
   2480           *miny = y1;
   2481         }
   2482         if (x2 > *maxx)
   2483         {
   2484           *maxx = x2;
   2485         }
   2486         if (y2 > *maxy)
   2487         {
   2488           *maxy = y2;
   2489         }
   2490         *x += (int16_t)textsize_x * xa;
   2491       }
   2492     }
   2493   }
   2494   else // not gfxFont
   2495 #endif // !defined(ATTINY_CORE)
   2496 #if defined(U8G2_FONT_SUPPORT)
   2497       if (u8g2Font)
   2498   {
   2499     _u8g2_decode_ptr = 0;
   2500 
   2501     if (_enableUTF8Print)
   2502     {
   2503       if (_utf8_state == 0)
   2504       {
   2505         if (c >= 0xfc) /* 6 byte sequence */
   2506         {
   2507           _utf8_state = 5;
   2508           c &= 1;
   2509         }
   2510         else if (c >= 0xf8)
   2511         {
   2512           _utf8_state = 4;
   2513           c &= 3;
   2514         }
   2515         else if (c >= 0xf0)
   2516         {
   2517           _utf8_state = 3;
   2518           c &= 7;
   2519         }
   2520         else if (c >= 0xe0)
   2521         {
   2522           _utf8_state = 2;
   2523           c &= 15;
   2524         }
   2525         else if (c >= 0xc0)
   2526         {
   2527           _utf8_state = 1;
   2528           c &= 0x01f;
   2529         }
   2530         _encoding = c;
   2531       }
   2532       else
   2533       {
   2534         _utf8_state--;
   2535         /* The case b < 0x080 (an illegal UTF8 encoding) is not checked here. */
   2536         _encoding <<= 6;
   2537         c &= 0x03f;
   2538         _encoding |= c;
   2539       }
   2540     } // _enableUTF8Print
   2541     else
   2542     {
   2543       _encoding = c;
   2544     }
   2545 
   2546     if (_utf8_state == 0)
   2547     {
   2548       if (_encoding == '\n')
   2549       {
   2550         *x = 0;
   2551         *y += (int16_t)textsize_y * _u8g2_max_char_height;
   2552       }
   2553       else if (_encoding != '\r')
   2554       { // Ignore carriage returns
   2555         uint8_t *font = u8g2Font;
   2556         const uint8_t *glyph_data = 0;
   2557 
   2558         // extract from u8g2_font_get_glyph_data()
   2559         font += 23; // U8G2_FONT_DATA_STRUCT_SIZE
   2560         if (_encoding <= 255)
   2561         {
   2562           if (_encoding >= 'a')
   2563           {
   2564             font += _u8g2_start_pos_lower_a;
   2565           }
   2566           else if (_encoding >= 'A')
   2567           {
   2568             font += _u8g2_start_pos_upper_A;
   2569           }
   2570 
   2571           for (;;)
   2572           {
   2573             if (pgm_read_byte(font + 1) == 0)
   2574               break;
   2575             if (pgm_read_byte(font) == _encoding)
   2576             {
   2577               glyph_data = font + 2; /* skip encoding and glyph size */
   2578             }
   2579             font += pgm_read_byte(font + 1);
   2580           }
   2581         }
   2582 #ifdef U8G2_WITH_UNICODE
   2583         else
   2584         {
   2585           uint16_t e;
   2586           font += _u8g2_start_pos_unicode;
   2587           const uint8_t *unicode_lookup_table = font;
   2588 
   2589           /* issue 596: search for the glyph start in the unicode lookup table */
   2590           do
   2591           {
   2592             font += u8g2_font_get_word(unicode_lookup_table, 0);
   2593             e = u8g2_font_get_word(unicode_lookup_table, 2);
   2594             unicode_lookup_table += 4;
   2595           } while (e < _encoding);
   2596 
   2597           for (;;)
   2598           {
   2599             e = u8g2_font_get_word(font, 0);
   2600 
   2601             if (e == 0)
   2602               break;
   2603 
   2604             if (e == _encoding)
   2605             {
   2606               glyph_data = font + 3; /* skip encoding and glyph size */
   2607               break;
   2608             }
   2609             font += pgm_read_byte(font + 2);
   2610           }
   2611         }
   2612 #endif
   2613 
   2614         if (glyph_data)
   2615         {
   2616           // u8g2_font_decode_glyph
   2617           _u8g2_decode_ptr = glyph_data;
   2618           _u8g2_decode_bit_pos = 0;
   2619 
   2620           _u8g2_char_width = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_char_width);
   2621           _u8g2_char_height = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_char_height);
   2622           _u8g2_char_x = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_char_x);
   2623           _u8g2_char_y = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_char_y);
   2624           _u8g2_delta_x = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_delta_x);
   2625           // log_d("c: %c, _encoding: %d, _u8g2_char_width: %d, _u8g2_char_height: %d, _u8g2_char_x: %d, _u8g2_char_y: %d, _u8g2_delta_x: %d",
   2626           //       c, _encoding, _u8g2_char_width, _u8g2_char_height, _u8g2_char_x, _u8g2_char_y, _u8g2_delta_x);
   2627 
   2628           if (_u8g2_char_width > 0)
   2629           {
   2630             if (wrap && ((*x + (textsize_x * _u8g2_char_width) - 1) > _max_x))
   2631             {
   2632               *x = 0;
   2633               *y += (int16_t)textsize_y * _u8g2_max_char_height;
   2634             }
   2635           }
   2636 
   2637           int16_t x1 = *x + ((int16_t)_u8g2_char_x * textsize_x),
   2638                   y1 = *y - (((int16_t)_u8g2_char_height + _u8g2_char_y) * textsize_y),
   2639                   x2 = x1 + ((int16_t)_u8g2_char_width * textsize_x) - 1,
   2640                   y2 = y1 + ((int16_t)_u8g2_char_height * textsize_y) - 1;
   2641           if (x1 < *minx)
   2642           {
   2643             *minx = x1;
   2644           }
   2645           if (y1 < *miny)
   2646           {
   2647             *miny = y1;
   2648           }
   2649           if (x2 > *maxx)
   2650           {
   2651             *maxx = x2;
   2652           }
   2653           if (y2 > *maxy)
   2654           {
   2655             *maxy = y2;
   2656           }
   2657           *x += (int16_t)textsize_x * _u8g2_delta_x;
   2658         }
   2659       }
   2660     }
   2661   }
   2662   else // glcdfont
   2663 #endif // defined(U8G2_FONT_SUPPORT)
   2664   {
   2665     if (c == '\n')
   2666     {                       // Newline?
   2667       *x = 0;               // Reset x to zero,
   2668       *y += textsize_y * 8; // advance y one line
   2669                             // min/max x/y unchaged -- that waits for next 'normal' character
   2670     }
   2671     else if (c != '\r') // Normal char; ignore carriage returns
   2672     {
   2673       if (wrap && ((*x + (textsize_x * 6) - 1) > _max_x)) // Off right?
   2674       {
   2675         *x = 0;               // Reset x to zero,
   2676         *y += textsize_y * 8; // advance y one line
   2677       }
   2678       int16_t x2 = *x + textsize_x * 6 - 1; // Lower-right pixel of char
   2679       int16_t y2 = *y + textsize_y * 8 - 1;
   2680       if (x2 > *maxx)
   2681       {
   2682         *maxx = x2; // Track max x, y
   2683       }
   2684       if (y2 > *maxy)
   2685       {
   2686         *maxy = y2;
   2687       }
   2688       if (*x < *minx)
   2689       {
   2690         *minx = *x; // Track min x, y
   2691       }
   2692       if (*y < *miny)
   2693       {
   2694         *miny = *y;
   2695       }
   2696       *x += textsize_x * 6; // Advance x one char
   2697     }
   2698   }
   2699 }
   2700 
   2701 /**************************************************************************/
   2702 /*!
   2703   @brief  Helper to determine size of a string with current font/size. Pass string and a cursor position, returns UL corner and W,H.
   2704   @param  str The ascii string to measure
   2705   @param  x   The current cursor X
   2706   @param  y   The current cursor Y
   2707   @param  x1  The boundary X coordinate, set by function
   2708   @param  y1  The boundary Y coordinate, set by function
   2709   @param  w   The boundary width, set by function
   2710   @param  h   The boundary height, set by function
   2711 */
   2712 /**************************************************************************/
   2713 void Arduino_GFX::getTextBounds(const char *str, int16_t x, int16_t y,
   2714                                 int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h)
   2715 {
   2716   uint8_t c; // Current character
   2717 
   2718   *x1 = x;
   2719   *y1 = y;
   2720   *w = *h = 0;
   2721 
   2722   int16_t minx = _width, miny = _height, maxx = -1, maxy = -1;
   2723 
   2724   while ((c = *str++))
   2725   {
   2726     charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);
   2727   }
   2728 
   2729   if (maxx >= minx)
   2730   {
   2731     *x1 = minx;
   2732     *w = maxx - minx + 1;
   2733   }
   2734   if (maxy >= miny)
   2735   {
   2736     *y1 = miny;
   2737     *h = maxy - miny + 1;
   2738   }
   2739 }
   2740 
   2741 /**************************************************************************/
   2742 /*!
   2743   @brief  Helper to determine size of a string with current font/size. Pass string and a cursor position, returns UL corner and W,H.
   2744   @param  str The ascii string to measure (as an arduino String() class)
   2745   @param  x   The current cursor X
   2746   @param  y   The current cursor Y
   2747   @param  x1  The boundary X coordinate, set by function
   2748   @param  y1  The boundary Y coordinate, set by function
   2749   @param  w   The boundary width, set by function
   2750   @param  h   The boundary height, set by function
   2751 */
   2752 /**************************************************************************/
   2753 void Arduino_GFX::getTextBounds(const String &str, int16_t x, int16_t y,
   2754                                 int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h)
   2755 {
   2756   if (str.length() != 0)
   2757   {
   2758     getTextBounds(const_cast<char *>(str.c_str()), x, y, x1, y1, w, h);
   2759   }
   2760 }
   2761 
   2762 /**************************************************************************/
   2763 /*!
   2764   @brief  Helper to determine size of a PROGMEM string with current font/size. Pass string and a cursor position, returns UL corner and W,H.
   2765   @param  str The flash-memory ascii string to measure
   2766   @param  x   The current cursor X
   2767   @param  y   The current cursor Y
   2768   @param  x1  The boundary X coordinate, set by function
   2769   @param  y1  The boundary Y coordinate, set by function
   2770   @param  w   The boundary width, set by function
   2771   @param  h   The boundary height, set by function
   2772 */
   2773 /**************************************************************************/
   2774 void Arduino_GFX::getTextBounds(const __FlashStringHelper *str,
   2775                                 int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h)
   2776 {
   2777   uint8_t *s = (uint8_t *)str, c;
   2778 
   2779   *x1 = x;
   2780   *y1 = y;
   2781   *w = *h = 0;
   2782 
   2783   int16_t minx = _width, miny = _height, maxx = -1, maxy = -1;
   2784 
   2785   while ((c = pgm_read_byte(s++)))
   2786     charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);
   2787 
   2788   if (maxx >= minx)
   2789   {
   2790     *x1 = minx;
   2791     *w = maxx - minx + 1;
   2792   }
   2793   if (maxy >= miny)
   2794   {
   2795     *y1 = miny;
   2796     *h = maxy - miny + 1;
   2797   }
   2798 }
   2799 
   2800 /**************************************************************************/
   2801 /*!
   2802   @brief  Invert the display (ideally using built-in hardware command)
   2803   @param  i   True if you want to invert, false to make 'normal'
   2804 */
   2805 /**************************************************************************/
   2806 void Arduino_GFX::invertDisplay(bool i)
   2807 {
   2808   // Do nothing, must be subclassed if supported by hardware
   2809   UNUSED(i);
   2810 }
   2811 
   2812 /**************************************************************************/
   2813 /*!
   2814   @brief  Turn on display after turned off
   2815 */
   2816 /**************************************************************************/
   2817 void Arduino_GFX::displayOn()
   2818 {
   2819 }
   2820 
   2821 /**************************************************************************/
   2822 /*!
   2823   @brief  Turn off display
   2824 */
   2825 /**************************************************************************/
   2826 void Arduino_GFX::displayOff()
   2827 {
   2828 }