From fddcf109614401a0a35acd3f42f2dbb42680600b Mon Sep 17 00:00:00 2001 From: Luke T Date: Mon, 22 Aug 2022 19:33:53 -0500 Subject: [PATCH 1/3] line_height function WIP --- lib/font_metrics.ex | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/lib/font_metrics.ex b/lib/font_metrics.ex index 8012221..80af4b3 100644 --- a/lib/font_metrics.ex +++ b/lib/font_metrics.ex @@ -175,6 +175,31 @@ defmodule FontMetrics do {x_min * scale, y_min * scale, x_max * scale, y_max * scale} end + # -------------------------------------------------------- + @doc """ + Return the height of a line of text. The response is scaled to the pixel size. + Adapted from this code: https://github.com/ScenicFramework/scenic_driver_local/blob/main/c_src/nanovg/fontstash.h#L964 + """ + @spec line_height(pixels :: number, metrics :: FontMetrics.t()) :: line_height :: number + def line_height(pixels, fm = %FontMetrics{ascent: ascent, descent: descent, max_box: {x_min, y_min, x_max, y_max}, line_gap: line_gap, units_per_em: u_p_m}) do + # test_line_gap = pixels - (ascender-descender) + # full_ascent = ascent + test_line_gap + # font_height = full_ascent - descent + # ascender = full_ascent / font_height + # descender = descent / font_height + + # require IEx; IEx.pry() + + # IO.inspect fm + + # line_height = ascender - descender + # scale = pixels / u_p_m + # line_height * pixels + # (y_max - y_min) * (pixels / u_p_m) + + (ascent + line_gap - descent) * (pixels / u_p_m) + end + # -------------------------------------------------------- @doc """ Measure the width of a string, scaled to a pixel size From fcee565a195effc89f1a4db5a3bf6ac4ee7ace68 Mon Sep 17 00:00:00 2001 From: Luke T Date: Sun, 16 Oct 2022 09:51:32 -0500 Subject: [PATCH 2/3] Change base case to zero not -1 --- lib/font_metrics.ex | 27 +-------------------------- test/font_metrics_test.exs | 27 +++++++++++++++++++++------ 2 files changed, 22 insertions(+), 32 deletions(-) diff --git a/lib/font_metrics.ex b/lib/font_metrics.ex index 80af4b3..35c818c 100644 --- a/lib/font_metrics.ex +++ b/lib/font_metrics.ex @@ -175,31 +175,6 @@ defmodule FontMetrics do {x_min * scale, y_min * scale, x_max * scale, y_max * scale} end - # -------------------------------------------------------- - @doc """ - Return the height of a line of text. The response is scaled to the pixel size. - Adapted from this code: https://github.com/ScenicFramework/scenic_driver_local/blob/main/c_src/nanovg/fontstash.h#L964 - """ - @spec line_height(pixels :: number, metrics :: FontMetrics.t()) :: line_height :: number - def line_height(pixels, fm = %FontMetrics{ascent: ascent, descent: descent, max_box: {x_min, y_min, x_max, y_max}, line_gap: line_gap, units_per_em: u_p_m}) do - # test_line_gap = pixels - (ascender-descender) - # full_ascent = ascent + test_line_gap - # font_height = full_ascent - descent - # ascender = full_ascent / font_height - # descender = descent / font_height - - # require IEx; IEx.pry() - - # IO.inspect fm - - # line_height = ascender - descender - # scale = pixels / u_p_m - # line_height * pixels - # (y_max - y_min) * (pixels / u_p_m) - - (ascent + line_gap - descent) * (pixels / u_p_m) - end - # -------------------------------------------------------- @doc """ Measure the width of a string, scaled to a pixel size @@ -628,7 +603,7 @@ defmodule FontMetrics do defp do_position_at(line, n, cp_metrics, kerning, kern, k_next \\ 0, line_no \\ 0, width \\ 0) defp do_position_at('', _, _, _, _, _, line_no, width), do: {width, line_no} - defp do_position_at(_, -1, _, _, _, _, line_no, width), do: {width, line_no} + defp do_position_at(_, p, _, _, _, _, line_no, width) when p <= 0, do: {width, line_no} # handle newlines defp do_position_at([10 | cps], n, cp_metrics, kerning, kern, _, line_no, _) do diff --git a/test/font_metrics_test.exs b/test/font_metrics_test.exs index f358223..0683c70 100644 --- a/test/font_metrics_test.exs +++ b/test/font_metrics_test.exs @@ -163,21 +163,36 @@ defmodule FontMetricsTest do test "position_at works with a simple string" do string = "PANCAKE breafasts are yummy" {w, 0} = FontMetrics.position_at(string, 8, 22, @roboto_metrics) - assert trunc(w) == 116 + assert trunc(w) == 104 {w, 0} = FontMetrics.position_at(string, 8, 22, @bitter_metrics) - assert trunc(w) == 123 + assert trunc(w) == 110 {w, 0} = FontMetrics.position_at(string, 8, 22, @bitter_metrics, kern: true) - assert trunc(w) == 121 + assert trunc(w) == 108 + end + + test "position_at returns zero length at position 0" do + string = "PANCAKE breafasts are yummy" + {w, 0} = FontMetrics.position_at(string, 0, 22, @roboto_metrics) + assert w == 0 + end + + test "with just one character, different positions in the string are multiples of the same width" do + string = "AAAAAAAAAA" # 10 chars long + {w, 0} = FontMetrics.position_at(string, 1, 22, @roboto_metrics) + {five_w, 0} = FontMetrics.position_at(string, 5, 22, @roboto_metrics) + assert 5*w == five_w + {ten_w, 0} = FontMetrics.position_at(string, 10, 22, @roboto_metrics) + assert 2*five_w == ten_w end test "position_at works with a multiline string" do string = "PANCAKE breafasts\nPANCAKE are yummy" {w, 1} = FontMetrics.position_at(string, 25, 22, @roboto_metrics) - assert trunc(w) == 104 + assert trunc(w) == 98 {w, 1} = FontMetrics.position_at(string, 25, 22, @bitter_metrics) - assert trunc(w) == 110 + assert trunc(w) == 105 {w, 1} = FontMetrics.position_at(string, 25, 22, @bitter_metrics, kern: true) - assert trunc(w) == 108 + assert trunc(w) == 103 end # ============================================================================ From db69d807caea7d19586371ccec15c9c710d8436a Mon Sep 17 00:00:00 2001 From: Luke T Date: Sun, 16 Oct 2022 10:07:43 -0500 Subject: [PATCH 3/3] add some extra tests --- test/font_metrics_test.exs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/font_metrics_test.exs b/test/font_metrics_test.exs index 0683c70..47f1b64 100644 --- a/test/font_metrics_test.exs +++ b/test/font_metrics_test.exs @@ -185,6 +185,19 @@ defmodule FontMetricsTest do assert 2*five_w == ten_w end + test "the length of an empty string is zero" do + {w1, 0} = FontMetrics.position_at("", 0, 22, @roboto_metrics) + {w2, 0} = FontMetrics.position_at("", 1, 22, @roboto_metrics) + assert w1 == 0 + assert w1 == w2 + end + + test "position one returns the same length as a one-character long string" do + {w1, 0} = FontMetrics.position_at("a", 1, 22, @roboto_metrics) + {w2, 0} = FontMetrics.position_at("aaaa", 1, 22, @roboto_metrics) + assert w1 == w2 + end + test "position_at works with a multiline string" do string = "PANCAKE breafasts\nPANCAKE are yummy" {w, 1} = FontMetrics.position_at(string, 25, 22, @roboto_metrics)