From e931bd03195afb749d0ea65fa5787ed2df082253 Mon Sep 17 00:00:00 2001
From: Ryan Oldenburg <guzba8@gmail.com>
Date: Fri, 7 May 2021 19:28:49 -0500
Subject: [PATCH] computeBounds, no iterator

---
 src/pixie.nim        | 36 ++++++++++++++++++++----------------
 src/pixie/fonts.nim  | 17 ++++++++++-------
 tests/test_fonts.nim |  7 +++++++
 3 files changed, 37 insertions(+), 23 deletions(-)

diff --git a/src/pixie.nim b/src/pixie.nim
index b8f86ac..d47afbb 100644
--- a/src/pixie.nim
+++ b/src/pixie.nim
@@ -341,13 +341,13 @@ proc fillText*(
 ) =
   ## Typesets and fills the text. Optional parameters:
   ## transform: translation or matrix to apply
-  ## bounds: width determines wrapping and halign, height for valign
+  ## bounds: width determines wrapping and hAlign, height for vAlign
   ## hAlign: horizontal alignment of the text
   ## vAlign: vertical alignment of the text
   ## textCase: text character case
   ## wrap: enable/disable text wrapping
   ## kerning: enable/disable kerning adjustments to letter spacing
-  for path in font.typeset(
+  let arrangement = font.typeset(
     text,
     bounds,
     hAlign,
@@ -355,8 +355,9 @@ proc fillText*(
     textCase,
     wrap,
     kerning
-  ).paths:
-    image.fillPath(path, color, transform)
+  )
+  for i in 0 ..< arrangement.runes.len:
+    image.fillPath(arrangement.getPath(i), color, transform)
 
 proc fillText*(
   mask: Mask,
@@ -372,13 +373,13 @@ proc fillText*(
 ) =
   ## Typesets and fills the text. Optional parameters:
   ## transform: translation or matrix to apply
-  ## bounds: width determines wrapping and halign, height for valign
+  ## bounds: width determines wrapping and hAlign, height for vAlign
   ## hAlign: horizontal alignment of the text
   ## vAlign: vertical alignment of the text
   ## textCase: text character case
   ## wrap: enable/disable text wrapping
   ## kerning: enable/disable kerning adjustments to letter spacing
-  for path in font.typeset(
+  let arrangement =  font.typeset(
     text,
     bounds,
     hAlign,
@@ -386,8 +387,9 @@ proc fillText*(
     textCase,
     wrap,
     kerning
-  ).paths:
-    mask.fillPath(path, transform)
+  )
+  for i in 0 ..< arrangement.runes.len:
+    mask.fillPath(arrangement.getPath(i), transform)
 
 proc strokeText*(
   image: Image,
@@ -405,13 +407,13 @@ proc strokeText*(
 ) =
   ## Typesets and strokes the text. Optional parameters:
   ## transform: translation or matrix to apply
-  ## bounds: width determines wrapping and halign, height for valign
+  ## bounds: width determines wrapping and hAlign, height for vAlign
   ## hAlign: horizontal alignment of the text
   ## vAlign: vertical alignment of the text
   ## textCase: text character case
   ## wrap: enable/disable text wrapping
   ## kerning: enable/disable kerning adjustments to letter spacing
-  for path in font.typeset(
+  let arrangement = font.typeset(
     text,
     bounds,
     hAlign,
@@ -419,8 +421,9 @@ proc strokeText*(
     textCase,
     wrap,
     kerning
-  ).paths:
-    image.strokePath(path, color, transform, strokeWidth)
+  )
+  for i in 0 ..< arrangement.runes.len:
+    image.strokePath(arrangement.getPath(i), color, transform, strokeWidth)
 
 proc strokeText*(
   mask: Mask,
@@ -437,13 +440,13 @@ proc strokeText*(
 ) =
   ## Typesets and strokes the text. Optional parameters:
   ## transform: translation or matrix to apply
-  ## bounds: width determines wrapping and halign, height for valign
+  ## bounds: width determines wrapping and hAlign, height for vAlign
   ## hAlign: horizontal alignment of the text
   ## vAlign: vertical alignment of the text
   ## textCase: text character case
   ## wrap: enable/disable text wrapping
   ## kerning: enable/disable kerning adjustments to letter spacing
-  for path in font.typeset(
+  let arrangement = font.typeset(
     text,
     bounds,
     hAlign,
@@ -451,5 +454,6 @@ proc strokeText*(
     textCase,
     wrap,
     kerning
-  ).paths:
-    mask.strokePath(path, transform, strokeWidth)
+  )
+  for i in 0 ..< arrangement.runes.len:
+    mask.strokePath(arrangement.getPath(i), transform, strokeWidth)
diff --git a/src/pixie/fonts.nim b/src/pixie/fonts.nim
index 423cbf8..cde4c3d 100644
--- a/src/pixie/fonts.nim
+++ b/src/pixie/fonts.nim
@@ -128,7 +128,7 @@ proc typeset*(
 ): Arrangement =
   ## Lays out the character glyphs and returns the arrangement.
   ## Optional parameters:
-  ## bounds: width determines wrapping and halign, height for valign
+  ## bounds: width determines wrapping and hAlign, height for vAlign
   ## hAlign: horizontal alignment of the text
   ## vAlign: vertical alignment of the text
   ## textCase: text character case
@@ -209,7 +209,7 @@ proc typeset*(
       result.selectionRects[i] = rect(at.x, at.y - initialY, advance, lineHeight)
       at.x += advance
 
-  if bounds.x > 0 and hAlign != haLeft:
+  if hAlign != haLeft:
     # Since horizontal alignment adjustments are different for each line,
     # find the start and stop of each line of text.
     var
@@ -244,7 +244,7 @@ proc typeset*(
           result.positions[i].x += xAdjustment
           result.selectionRects[i].x += xAdjustment
 
-  if bounds.y > 0:
+  if vAlign != vaTop:
     let
       finalSelectionRect = result.selectionRects[^1]
       furthestY = finalSelectionRect.y + finalSelectionRect.h
@@ -271,10 +271,13 @@ proc getPath*(arrangement: Arrangement, index: int): Path =
     scale(vec2(arrangement.font.scale))
   )
 
-iterator paths*(arrangement: Arrangement): Path =
-  ## Iterates over the paths for the arrangement.
-  for i in 0 ..< arrangement.runes.len:
-    yield arrangement.getPath(i)
+proc computeBounds*(font: Font, text: string): Vec2 =
+  let arrangement = font.typeset(text)
+  if arrangement.runes.len > 0:
+    for rect in arrangement.selectionRects:
+      result.x = max(result.x, rect.x + rect.w)
+    let finalRect = arrangement.selectionRects[^1]
+    result.y = finalRect.y + finalRect.h
 
 proc parseOtf*(buf: string): Font =
   result.typeface = Typeface()
diff --git a/tests/test_fonts.nim b/tests/test_fonts.nim
index 0cf985e..9d551f8 100644
--- a/tests/test_fonts.nim
+++ b/tests/test_fonts.nim
@@ -8,6 +8,13 @@ proc doDiff(rendered: Image, name: string) =
   echo &"{name} score: {diffScore}"
   diffImage.writeFile(&"tests/fonts/diffs/{name}.png")
 
+block:
+  var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
+  font.size = 24
+
+  let bounds = font.computeBounds("Word")
+  doAssert bounds == vec2(56.05078125, 28)
+
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
   font.size = 64