Commit 9983e9c6 for tesseract

commit 9983e9c69ac49e0ee2a6d05204879ae5ec3481b6
Author: Stefan Weil <sw@weilnetz.de>
Date:   Sun Aug 9 15:13:39 2026 +0200

    Fix CID 1660582 (Division or modulo by float zero)

    make_prop_words divided the gap size by row->space_size, which is 0
    for degenerate rows (TO_ROW::clear() initializes it to 0). Use a
    guarded local divisor instead.

    Assisted-by: OpenCode / big-pickle (opencode)
    Signed-off-by: Stefan Weil <sw@weilnetz.de>

diff --git a/src/textord/tospace.cpp b/src/textord/tospace.cpp
index 1684bb31..8c5a5b6a 100644
--- a/src/textord/tospace.cpp
+++ b/src/textord/tospace.cpp
@@ -870,6 +870,12 @@ the gap between the word being built and the next one. */
   int16_t current_within_xht_gap = INT16_MAX;
   int16_t next_within_xht_gap = INT16_MAX;
   int16_t word_count = 0;
+  // Degenerate rows may have space_size 0, so guard against division by zero.
+  // A fallback larger than any int16_t gap yields floor(gap / space_size) == 0,
+  // so the blank count is raised to 1 by the checks below.
+  const float space_size = row->space_size > 0.0f
+                               ? row->space_size
+                               : static_cast<float>(INT16_MAX) + 1.0f;

   // repeated char words
   WERD_IT rep_char_it(&(row->rep_words));
@@ -905,7 +911,7 @@ the gap between the word being built and the next one. */
       current_gap = box_it.data()->bounding_box().left() - next_rep_char_word_right;
       current_within_xht_gap = current_gap;
       if (current_gap > tosp_rep_space * repetition_spacing) {
-        prev_blanks = static_cast<uint8_t>(std::floor(current_gap / row->space_size));
+        prev_blanks = static_cast<uint8_t>(std::floor(current_gap / space_size));
         if (prev_blanks < 1) {
           prev_blanks = 1;
         }
@@ -998,7 +1004,7 @@ the gap between the word being built and the next one. */
             current_gap = word->bounding_box().left() - prev_x;
             current_within_xht_gap = current_gap;
             if (current_gap > tosp_rep_space * repetition_spacing) {
-              blanks = static_cast<uint8_t>(std::floor(current_gap / row->space_size));
+              blanks = static_cast<uint8_t>(std::floor(current_gap / space_size));
               if (blanks < 1) {
                 blanks = 1;
               }
@@ -1019,7 +1025,7 @@ the gap between the word being built and the next one. */
              */
             current_gap = blob_box.left() - next_rep_char_word_right;
             if (current_gap > tosp_rep_space * repetition_spacing) {
-              blanks = static_cast<uint8_t>(current_gap / row->space_size);
+              blanks = static_cast<uint8_t>(current_gap / space_size);
               if (blanks < 1) {
                 blanks = 1;
               }
@@ -1062,7 +1068,7 @@ the gap between the word being built and the next one. */
       repetition_spacing = find_mean_blob_spacing(word);
       current_gap = word->bounding_box().left() - prev_x;
       if (current_gap > tosp_rep_space * repetition_spacing) {
-        blanks = static_cast<uint8_t>(std::floor(current_gap / row->space_size));
+        blanks = static_cast<uint8_t>(std::floor(current_gap / space_size));
         if (blanks < 1) {
           blanks = 1;
         }