diff --git a/src/pixie/fonts.nim b/src/pixie/fonts.nim index da49b4c..e4a8ebd 100644 --- a/src/pixie/fonts.nim +++ b/src/pixie/fonts.nim @@ -139,6 +139,10 @@ proc typeset*( if rune.uint32 >= SP.uint32 or rune.uint32 == LF.uint32: result.runes.add(rune) + if result.runes.len == 0: + # No runes to typeset, early return + return + result.runes.convertTextCase(textCase) result.positions.setLen(result.runes.len) result.selectionRects.setLen(result.runes.len) @@ -197,6 +201,60 @@ proc typeset*( result.selectionRects[i] = rect(at.x, at.y - initialY, advance, lineHeight) at.x += advance + if bounds.x > 0 and hAlign != haLeft: + # Since horizontal alignment adjustments are different for each line, + # find the start and stop of each line of text. + var + lines: seq[(int, int)] # (start, stop) + start: int + prevY = result.positions[0].y + for i, pos in result.positions: + if pos.y != prevY: + lines.add((start, i - 1)) + start = i + prevY = pos.y + lines.add((start, result.positions.len - 1)) + + for (start, stop) in lines: + var furthestX: float32 + for i in countdown(stop, start): + if result.runes[i] != SP and result.runes[i] != LF: + furthestX = result.selectionRects[i].x + result.selectionRects[i].w + break + + var xAdjustment: float32 + case hAlign: + of haLeft: + discard + of haCenter: + xAdjustment = round((bounds.x - furthestX) / 2) + of haRight: + xAdjustment = bounds.x - furthestX + + if xAdjustment != 0: + for i in 0 ..< result.positions.len: + result.positions[i].x += xAdjustment + result.selectionRects[i].x += xAdjustment + + if bounds.y > 0: + let + finalSelectionRect = result.selectionRects[^1] + furthestY = finalSelectionRect.y + finalSelectionRect.h + + var yAdjustment: float32 + case vAlign: + of vaTop: + discard + of vaMiddle: + yAdjustment = round((bounds.y - furthestY) / 2) + of vaBottom: + yAdjustment = bounds.y - furthestY + + if yAdjustment != 0: + for i in 0 ..< result.positions.len: + result.positions[i].y += yAdjustment + result.selectionRects[i].y += yAdjustment + iterator paths*(arrangement: Arrangement): Path = for i in 0 ..< arrangement.runes.len: if arrangement.runes[i].uint32 > SP.uint32: # Don't draw control runes diff --git a/tests/fonts/diffs/alignments.png b/tests/fonts/diffs/alignments.png new file mode 100644 index 0000000..fe4a184 Binary files /dev/null and b/tests/fonts/diffs/alignments.png differ diff --git a/tests/fonts/masters/alignments.png b/tests/fonts/masters/alignments.png new file mode 100644 index 0000000..9e267e4 Binary files /dev/null and b/tests/fonts/masters/alignments.png differ diff --git a/tests/fonts/rendered/alignments.png b/tests/fonts/rendered/alignments.png new file mode 100644 index 0000000..0c4f480 Binary files /dev/null and b/tests/fonts/rendered/alignments.png differ diff --git a/tests/fonts_megatest.nim b/tests/fonts_megatest.nim index 157d6f2..f76f15c 100644 --- a/tests/fonts_megatest.nim +++ b/tests/fonts_megatest.nim @@ -1,11 +1,12 @@ -import common, pixie, flatty/memoryused +import common, pixie -# Clone https://github.com/google/fonts -# Check out commit ebaa6a7aab9b700da4e30a4682687acdf427eae7 +# Clone https://github.com/treeform/fidgetfonts -let fontPaths = findAllFonts("../fonts") +let fontPaths = findAllFonts("../fidgetfonts") for fontPath in fontPaths: echo fontPath - let font = readFont(fontPath) - # echo memoryUsed(font) + try: + var font = readFont(fontPath) + except PixieError: + echo "ERROR: ", getCurrentExceptionMsg() diff --git a/tests/test_fonts.nim b/tests/test_fonts.nim index de43441..0cf985e 100644 --- a/tests/test_fonts.nim +++ b/tests/test_fonts.nim @@ -553,3 +553,93 @@ Fifth line""", ) doDiff(image, "lines2") + +block: + var font = readFont("tests/fonts/Roboto-Regular_1.ttf") + font.size = 36 + + let image = newImage(800, 800) + image.fill(rgba(255, 255, 255, 255)) + + image.fillText( + font, + "TopLeft", + rgba(0, 0, 0, 255), + bounds = image.wh, + hAlign = haLeft, + vAlign = vaTop + ) + + image.fillText( + font, + "TopCenter", + rgba(0, 0, 0, 255), + bounds = image.wh, + hAlign = haCenter, + vAlign = vaTop + ) + + image.fillText( + font, + "TopRight", + rgba(0, 0, 0, 255), + bounds = image.wh, + hAlign = haRight, + vAlign = vaTop + ) + + image.fillText( + font, + "MiddleLeft", + rgba(0, 0, 0, 255), + bounds = image.wh, + hAlign = haLeft, + vAlign = vaMiddle + ) + + image.fillText( + font, + "MiddleCenter", + rgba(0, 0, 0, 255), + bounds = image.wh, + hAlign = haCenter, + vAlign = vaMiddle + ) + + image.fillText( + font, + "MiddleRight", + rgba(0, 0, 0, 255), + bounds = image.wh, + hAlign = haRight, + vAlign = vaMiddle + ) + + image.fillText( + font, + "BottomLeft", + rgba(0, 0, 0, 255), + bounds = image.wh, + hAlign = haLeft, + vAlign = vaBottom + ) + + image.fillText( + font, + "BottomCenter", + rgba(0, 0, 0, 255), + bounds = image.wh, + hAlign = haCenter, + vAlign = vaBottom + ) + + image.fillText( + font, + "BottomRight", + rgba(0, 0, 0, 255), + bounds = image.wh, + hAlign = haRight, + vAlign = vaBottom + ) + + doDiff(image, "alignments")