diff --git a/pixie.nimble b/pixie.nimble index 8495e43..e5ef86c 100644 --- a/pixie.nimble +++ b/pixie.nimble @@ -1,4 +1,4 @@ -version = "4.0.0" +version = "4.0.1" author = "Andre von Houck and Ryan Oldenburg" description = "Full-featured 2d graphics library for Nim." license = "MIT" diff --git a/src/pixie/fonts.nim b/src/pixie/fonts.nim index cd5a24e..4a5bf7e 100644 --- a/src/pixie/fonts.nim +++ b/src/pixie/fonts.nim @@ -82,6 +82,7 @@ proc lineGap*(typeface: Typeface): float32 {.raises: [].} = proc lineHeight*(typeface: Typeface): float32 {.inline, raises: [].} = ## The default line height in font units. + # The descent is negative number, so this is really ascent + descent + lineGap. typeface.ascent - typeface.descent + typeface.lineGap proc underlinePosition(typeface: Typeface): float32 = @@ -186,6 +187,18 @@ proc defaultLineHeight*(font: Font): float32 {.inline, raises: [].} = font.typeface.ascent - font.typeface.descent + font.typeface.lineGap round(fontUnits * font.scale) +proc lineGap(font: Font): float32 = + ## The line gap in font units for the current font size and line-height. + let lineHeight = + if font.lineHeight >= 0: + font.lineHeight + else: + font.defaultLineHeight + if lineHeight == font.defaultLineHeight: + font.typeface.lineGap + else: + (lineHeight / font.scale) - font.typeface.ascent + font.typeface.descent + proc paint*(font: Font): Paint {.inline, raises: [].} = font.paints[0] @@ -356,20 +369,10 @@ proc typeset*( for spanIndex, (start, stop) in result.spans: let font = result.fonts[spanIndex] - lineHeight = - if font.lineHeight >= 0: - font.lineHeight - else: - font.defaultLineHeight - var fontUnitInitialY = font.typeface.ascent + font.typeface.lineGap / 2 - if lineHeight != font.defaultLineHeight: - fontUnitInitialY += ( - (lineHeight / font.scale) - font.typeface.lineHeight - ) / 2 + fontUnitInitialY = font.typeface.ascent + font.lineGap / 2 maxInitialY = max(maxInitialY, round(fontUnitInitialY * font.scale)) - for runeIndex in start .. stop: - if runeIndex == result.lines[0][1]: - break outer + if stop >= result.lines[0][1]: + break outer maxInitialY var lineHeights = newSeq[float32](result.lines.len) @@ -385,6 +388,8 @@ proc typeset*( font.defaultLineHeight lineHeights[line] = max(lineHeights[line], fontLineHeight) for runeIndex in start .. stop: + # This span could be many lines. This check can be made faster by + # hopping based on line endings instead of checking each index. if line + 1 < result.lines.len and runeIndex == result.lines[line + 1][0]: inc line @@ -401,8 +406,8 @@ proc typeset*( let font = result.fonts[spanIndex] lineHeight = - if font.lineheight >= 0: - font.lineheight + if font.lineHeight >= 0: + font.lineHeight else: font.defaultLineHeight for runeIndex in start .. stop: @@ -411,8 +416,8 @@ proc typeset*( inc line baseline += lineHeights[line] result.positions[runeIndex].y = baseline - result.selectionRects[runeIndex].y = - baseline - round(font.typeface.ascent * font.scale) + result.selectionRects[runeIndex].y = baseline - + round((font.typeface.ascent + font.lineGap / 2) * font.scale) result.selectionRects[runeIndex].h = lineHeight if vAlign != TopAlign: diff --git a/tests/fonts/Inter-Bold.ttf b/tests/fonts/Inter-Bold.ttf new file mode 100644 index 0000000..0487c21 Binary files /dev/null and b/tests/fonts/Inter-Bold.ttf differ diff --git a/tests/fonts/diffs/customlineheight.png b/tests/fonts/diffs/customlineheight.png new file mode 100644 index 0000000..ccce547 Binary files /dev/null and b/tests/fonts/diffs/customlineheight.png differ diff --git a/tests/fonts/diffs/selection_rects1.png b/tests/fonts/diffs/selection_rects1.png index 7fbd686..9740412 100644 Binary files a/tests/fonts/diffs/selection_rects1.png and b/tests/fonts/diffs/selection_rects1.png differ diff --git a/tests/fonts/diffs/selection_rects2.png b/tests/fonts/diffs/selection_rects2.png index 6f0d765..1b287eb 100644 Binary files a/tests/fonts/diffs/selection_rects2.png and b/tests/fonts/diffs/selection_rects2.png differ diff --git a/tests/fonts/masters/customlineheight.png b/tests/fonts/masters/customlineheight.png new file mode 100644 index 0000000..9e162bc Binary files /dev/null and b/tests/fonts/masters/customlineheight.png differ diff --git a/tests/fonts/rendered/customlineheight.png b/tests/fonts/rendered/customlineheight.png new file mode 100644 index 0000000..03bc16a Binary files /dev/null and b/tests/fonts/rendered/customlineheight.png differ diff --git a/tests/fonts/rendered/selection_rects1.png b/tests/fonts/rendered/selection_rects1.png index c7ceba0..7ccf0cc 100644 Binary files a/tests/fonts/rendered/selection_rects1.png and b/tests/fonts/rendered/selection_rects1.png differ diff --git a/tests/fonts/rendered/selection_rects2.png b/tests/fonts/rendered/selection_rects2.png index 3a9536a..0ab87b5 100644 Binary files a/tests/fonts/rendered/selection_rects2.png and b/tests/fonts/rendered/selection_rects2.png differ diff --git a/tests/test_fonts.nim b/tests/test_fonts.nim index 8d81311..71c9b9b 100644 --- a/tests/test_fonts.nim +++ b/tests/test_fonts.nim @@ -1101,3 +1101,61 @@ block: image.fillText(font, "This[]Advance!") doDiff(image, "tofu_advance") + +block: + let image = newImage(200, 200) + image.fill(color(1, 1, 1, 1)) + + let paint = newPaint(SolidPaint) + paint.color = color(1, 0, 0, 1) + + let ctx = newContext(image) + ctx.lineWidth = 1 + ctx.strokeStyle = paint + ctx.strokeRect(0, 60, 200, 80) + + let text = "AbCd\naBcD" + + let font = pixie.read_font("tests/fonts/Inter-Bold.ttf") + font.size = 40 + font.line_height = 27 + + let arrangement1 = font.typeset( + text, + vec2(200, 80), + CenterAlign, + TopAlign + ) + + # let p1 = newPath() + # p1.rect(arrangement1.selectionRects[0]) + # image.fillpath(p1, rgba(196, 196, 196, 255), translate(vec2(0, 266))) + + font.paint.color = color(1, 0, 0, 1) + image.fillText(arrangement1, translate(vec2(0, 60))) + + let arrangement2 = font.typeset( + text, + vec2(200, 80), + CenterAlign, + MiddleAlign + ) + + # let p2 = newPath() + # p2.rect(arrangement2.selectionRects[0]) + # image.fillpath(p2, rgba(196, 196, 196, 255), translate(vec2(0, 266))) + + font.paint.color = color(0, 1, 0, 1) + image.fillText(arrangement2, translate(vec2(0, 60))) + + font.paint.color = color(0, 0, 1, 1) + image.fillText( + font, + text, + bounds = vec2(200, 80), + hAlign = CenterAlign, + vAlign = BottomAlign, + transform = translate(vec2(0, 60)) + ) + + doDiff(image, "customlineheight") diff --git a/tests/test_paints.nim b/tests/test_paints.nim index f008e8f..f0a800a 100644 --- a/tests/test_paints.nim +++ b/tests/test_paints.nim @@ -14,7 +14,7 @@ block: heartShape, rgba(255, 0, 0, 255) ) - image.writeFile("tests/paths/SolidPaint.png") + image.writeFile("tests/paths/paintSolid.png") block: let paint = newPaint(ImagePaint) @@ -23,7 +23,7 @@ block: let image = newImage(100, 100) image.fillPath(heartShape, paint) - image.writeFile("tests/paths/ImagePaint.png") + image.writeFile("tests/paths/paintImage.png") block: let paint = newPaint(ImagePaint) @@ -42,7 +42,7 @@ block: let image = newImage(100, 100) image.fillPath(heartShape, paint) - image.writeFile("tests/paths/TiledImagePaint.png") + image.writeFile("tests/paths/paintImageTiled.png") block: let paint = newPaint(TiledImagePaint)