From 6d0361ae0892952fad46bc1838cfed37f9533b49 Mon Sep 17 00:00:00 2001
From: Fabrice Weinberg <Fabrice@weinberg.me>
Date: Sun, 10 Jan 2016 20:12:37 +0100
Subject: [PATCH] Improve drawStringMax performance

---
 SSD1306.cpp | 50 +++++++++++++++++++++++++++++++++-----------------
 SSD1306.h   |  8 ++------
 2 files changed, 35 insertions(+), 23 deletions(-)

diff --git a/SSD1306.cpp b/SSD1306.cpp
index 2d13709..1c23328 100644
--- a/SSD1306.cpp
+++ b/SSD1306.cpp
@@ -297,29 +297,45 @@ void SSD1306::drawString(int16_t xMove, int16_t yMove, String strUser) {
   free(text);
 }
 
-void SSD1306::drawStringMaxWidth(int16_t x, int16_t y, int16_t maxLineWidth, String text) {
-  uint16_t startsAt = 0;
-  uint16_t endsAt = 0;
-  uint16_t lineNumber = 0;
+void SSD1306::drawStringMaxWidth(int16_t xMove, int16_t yMove, uint16_t maxLineWidth, String strUser) {
+  uint16_t firstChar  = pgm_read_byte(fontData + FIRST_CHAR_POS);
   uint16_t lineHeight = pgm_read_byte(fontData + HEIGHT_POS);
-  String currentLine = "";
-  uint16_t length = text.length();
+
+  char* text = utf8ascii(strUser);
+
+  uint16_t length = strlen(text);
+  uint16_t lastDrawnPos = 0;
+  uint16_t lineNumber = 0;
+  uint16_t strWidth = 0;
+
+  uint16_t preferredBreakpoint = 0;
+  uint16_t widthAtBreakpoint = 0;
+
   for (uint16_t i = 0; i < length; i++) {
-    char currentChar = text.charAt(i);
-    if (currentChar == ' ' || currentChar == '-') {
-      String lineCandidate = text.substring(startsAt, i);
-      if (getStringWidth(lineCandidate.c_str()) <= maxLineWidth) {
-        endsAt = i;
-      } else {
-        drawString(x, y + lineNumber * lineHeight, text.substring(startsAt, endsAt));
-        lineNumber++;
-        startsAt = endsAt + 1;
-      }
+    strWidth += pgm_read_byte(fontData + JUMPTABLE_START + (text[i] - firstChar) * JUMPTABLE_BYTES + JUMPTABLE_WIDTH);
+
+    // Always try to break on a space or dash
+    if (text[i] == ' ' || text[i]== '-') {
+      preferredBreakpoint = i;
+      widthAtBreakpoint = strWidth;
+    }
+
+    if (strWidth >= maxLineWidth) {
+      preferredBreakpoint = preferredBreakpoint ? preferredBreakpoint : i;
+      widthAtBreakpoint = preferredBreakpoint ? widthAtBreakpoint : strWidth;
+
+      drawStringInternal(xMove, yMove + (lineNumber++) * lineHeight , &text[lastDrawnPos], preferredBreakpoint - lastDrawnPos, widthAtBreakpoint);
+
+      lastDrawnPos = preferredBreakpoint + 1; strWidth = 0; preferredBreakpoint = 0;
     }
+  }
 
+  // Draw last part if needed
+  if (lastDrawnPos < length) {
+    drawStringInternal(xMove, yMove + lineNumber * lineHeight , &text[lastDrawnPos], length - lastDrawnPos, getStringWidth(&text[lastDrawnPos], length - lastDrawnPos));
   }
 
-  drawString(x, y + lineNumber * lineHeight, text.substring(startsAt));
+  free(text);
 }
 
 uint16_t SSD1306::getStringWidth(const char* text, uint16_t length) {
diff --git a/SSD1306.h b/SSD1306.h
index 1878f88..ee9a7b8 100644
--- a/SSD1306.h
+++ b/SSD1306.h
@@ -132,7 +132,7 @@ class SSD1306 {
     byte utf8ascii(byte ascii);
     char* utf8ascii(String s);
 
-    void drawInternal(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *data, uint16_t offset, uint16_t bytesInData);
+    void drawInternal(int16_t xMove, int16_t yMove, int16_t width, int16_t height, const char *data, uint16_t offset, uint16_t bytesInData) __attribute__((always_inline));
 
     void drawStringInternal(int16_t xMove, int16_t yMove, char* text, uint16_t textLength, uint16_t textWidth);
   public:
@@ -186,11 +186,7 @@ class SSD1306 {
     // Draws a String with a maximum width at the given location.
     // If the given String is wider than the specified width
     // The text will be wrapped to the next line at a space or dash
-    void drawStringMaxWidth(int16_t x, int16_t y, int16_t maxLineWidth, String text);
-
-    // Returns the width of the const char* with the current
-    // font settings
-    uint16_t getStringWidth(const char* text);
+    void drawStringMaxWidth(int16_t x, int16_t y, uint16_t maxLineWidth, String text);
 
     // Specifies relative to which anchor point
     // the text is rendered. Available constants:
-- 
GitLab