SDL_ttf: Better carriage-return + newline handling

From 0abb68ebba86d3d53a63446eeb149c691bb3cb77 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 3 Oct 2024 22:40:26 -0700
Subject: [PATCH] Better carriage-return + newline handling

---
 examples/editbox.c | 26 +++++++++++++-------------
 src/SDL_ttf.c      |  8 ++++++--
 2 files changed, 19 insertions(+), 15 deletions(-)

diff --git a/examples/editbox.c b/examples/editbox.c
index 22fbef48..15d3a27d 100644
--- a/examples/editbox.c
+++ b/examples/editbox.c
@@ -14,18 +14,6 @@
 #define CURSOR_BLINK_INTERVAL_MS    500
 
 
-static bool GetHighlightExtents(EditBox *edit, int *marker1, int *marker2)
-{
-    if (edit->highlight1 >= 0 && edit->highlight2 >= 0) {
-        *marker1 = SDL_min(edit->highlight1, edit->highlight2);
-        *marker2 = SDL_max(edit->highlight1, edit->highlight2) - 1;
-        if (*marker2 > *marker1) {
-            return true;
-        }
-    }
-    return false;
-}
-
 EditBox *EditBox_Create(TTF_Text *text, const SDL_FRect *rect)
 {
     EditBox *edit = (EditBox *)SDL_calloc(1, sizeof(*edit));
@@ -51,6 +39,18 @@ void EditBox_Destroy(EditBox *edit)
     SDL_free(edit);
 }
 
+static bool GetHighlightExtents(EditBox *edit, int *marker1, int *marker2)
+{
+    if (edit->highlight1 >= 0 && edit->highlight2 >= 0) {
+        *marker1 = SDL_min(edit->highlight1, edit->highlight2);
+        *marker2 = SDL_max(edit->highlight1, edit->highlight2) - 1;
+        if (*marker2 > *marker1) {
+            return true;
+        }
+    }
+    return false;
+}
+
 void EditBox_Draw(EditBox *edit, SDL_Renderer *renderer)
 {
     if (!edit) {
@@ -137,7 +137,7 @@ static void MoveCursorIndex(EditBox *edit, int direction)
         }
     } else {
         if (TTF_GetTextSubString(edit->text, edit->cursor, &substring) &&
-            TTF_GetTextSubString(edit->text, substring.offset + substring.length, &substring)) {
+            TTF_GetTextSubString(edit->text, substring.offset + SDL_max(substring.length, 1), &substring)) {
             edit->cursor = substring.offset;
         }
     }
diff --git a/src/SDL_ttf.c b/src/SDL_ttf.c
index b2817711..e0ce10cd 100644
--- a/src/SDL_ttf.c
+++ b/src/SDL_ttf.c
@@ -3449,7 +3449,7 @@ static bool GetWrappedLines(TTF_Font *font, const char *text, size_t length, int
                     save_text = spot;
                     save_length = left;
                     // Break, if new line
-                    if (c == '\n' || c == '\r') {
+                    if (c == '\n' || (c == '\r' && *spot != '\n')) {
                         break;
                     }
                 }
@@ -3472,7 +3472,7 @@ static bool GetWrappedLines(TTF_Font *font, const char *text, size_t length, int
             TTF_Line *line = &strLines[i];
             while (line->length > 0 &&
                    CharacterIsDelimiter(line->text[line->length - 1]) &&
-                   line->text[line->length - 1] != '\n') {
+                   !CharacterIsNewLine(line->text[line->length - 1])) {
                 --line->length;
             }
         }
@@ -3854,6 +3854,10 @@ static bool LayoutTextWrapped(TTF_Text *text)
     for (i = 0; i < numLines; i++) {
         int xstart, ystart, line_width, xoffset;
 
+        if (strLines[i].length == 0) {
+            continue;
+        }
+
         // Initialize xstart, ystart and compute positions
         if (!TTF_Size_Internal(font, strLines[i].text, strLines[i].length, &line_width, NULL, &xstart, &ystart, NO_MEASUREMENT)) {
             goto done;