mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-29 04:09:13 +00:00
LibGfx+LibWeb: Simplify text shaping API by removing per glyph callback
All places where text shaping happens, the callback is used to simply append a glyph into the end of glyphs vector. This change removes the callback parameter and makes the text shaping function return a glyph run.
This commit is contained in:
parent
60fa3752ee
commit
17f4ed6ea1
Notes:
github-actions[bot]
2024-09-15 13:43:30 +00:00
Author: https://github.com/kalenikaliaksandr
Commit: 17f4ed6ea1
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1402
5 changed files with 19 additions and 42 deletions
|
@ -12,7 +12,7 @@
|
|||
|
||||
namespace Gfx {
|
||||
|
||||
void for_each_glyph_position(FloatPoint baseline_start, Utf8View string, Gfx::Font const& font, Function<void(DrawGlyph const&)> callback, Optional<float&> width)
|
||||
RefPtr<GlyphRun> shape_text(FloatPoint baseline_start, Utf8View string, Gfx::Font const& font, GlyphRun::TextType text_type)
|
||||
{
|
||||
hb_buffer_t* buffer = hb_buffer_create();
|
||||
ScopeGuard destroy_buffer = [&]() { hb_buffer_destroy(buffer); };
|
||||
|
@ -22,8 +22,6 @@ void for_each_glyph_position(FloatPoint baseline_start, Utf8View string, Gfx::Fo
|
|||
u32 glyph_count;
|
||||
auto* glyph_info = hb_buffer_get_glyph_infos(buffer, &glyph_count);
|
||||
Vector<hb_glyph_info_t> const input_glyph_info({ glyph_info, glyph_count });
|
||||
if (input_glyph_info.is_empty())
|
||||
return;
|
||||
|
||||
auto* hb_font = font.harfbuzz_font();
|
||||
hb_shape(hb_font, buffer, nullptr, 0);
|
||||
|
@ -31,27 +29,23 @@ void for_each_glyph_position(FloatPoint baseline_start, Utf8View string, Gfx::Fo
|
|||
glyph_info = hb_buffer_get_glyph_infos(buffer, &glyph_count);
|
||||
auto* positions = hb_buffer_get_glyph_positions(buffer, &glyph_count);
|
||||
|
||||
Vector<Gfx::DrawGlyph> glyph_run;
|
||||
FloatPoint point = baseline_start;
|
||||
for (size_t i = 0; i < glyph_count; ++i) {
|
||||
auto position = point
|
||||
- FloatPoint { 0, font.pixel_metrics().ascent }
|
||||
+ FloatPoint { positions[i].x_offset, positions[i].y_offset } / text_shaping_resolution;
|
||||
callback(DrawGlyph {
|
||||
.position = position,
|
||||
.glyph_id = glyph_info[i].codepoint,
|
||||
});
|
||||
glyph_run.append({ position, glyph_info[i].codepoint });
|
||||
point += FloatPoint { positions[i].x_advance, positions[i].y_advance } / text_shaping_resolution;
|
||||
}
|
||||
|
||||
if (width.has_value())
|
||||
*width = point.x();
|
||||
return adopt_ref(*new Gfx::GlyphRun(move(glyph_run), font, text_type, point.x()));
|
||||
}
|
||||
|
||||
float measure_text_width(Utf8View const& string, Gfx::Font const& font)
|
||||
{
|
||||
float width = 0;
|
||||
for_each_glyph_position({}, string, font, [&](DrawGlyph const&) {}, width);
|
||||
return width;
|
||||
auto glyph_run = shape_text({}, string, font, GlyphRun::TextType::Common);
|
||||
return glyph_run->width();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,10 +40,11 @@ public:
|
|||
Rtl,
|
||||
};
|
||||
|
||||
GlyphRun(Vector<DrawGlyph>&& glyphs, NonnullRefPtr<Font> font, TextType text_type)
|
||||
GlyphRun(Vector<DrawGlyph>&& glyphs, NonnullRefPtr<Font> font, TextType text_type, float width)
|
||||
: m_glyphs(move(glyphs))
|
||||
, m_font(move(font))
|
||||
, m_text_type(text_type)
|
||||
, m_width(width)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -52,6 +53,7 @@ public:
|
|||
[[nodiscard]] Vector<DrawGlyph> const& glyphs() const { return m_glyphs; }
|
||||
[[nodiscard]] Vector<DrawGlyph>& glyphs() { return m_glyphs; }
|
||||
[[nodiscard]] bool is_empty() const { return m_glyphs.is_empty(); }
|
||||
[[nodiscard]] float width() const { return m_width; }
|
||||
|
||||
void append(DrawGlyph glyph) { m_glyphs.append(glyph); }
|
||||
|
||||
|
@ -59,9 +61,10 @@ private:
|
|||
Vector<DrawGlyph> m_glyphs;
|
||||
NonnullRefPtr<Font> m_font;
|
||||
TextType m_text_type;
|
||||
float m_width { 0 };
|
||||
};
|
||||
|
||||
void for_each_glyph_position(FloatPoint baseline_start, Utf8View string, Gfx::Font const& font, Function<void(DrawGlyph const&)> callback, Optional<float&> width = {});
|
||||
RefPtr<GlyphRun> shape_text(FloatPoint baseline_start, Utf8View string, Gfx::Font const& font, GlyphRun::TextType);
|
||||
float measure_text_width(Utf8View const& string, Gfx::Font const& font);
|
||||
|
||||
}
|
||||
|
|
|
@ -513,16 +513,10 @@ CanvasRenderingContext2D::PreparedText CanvasRenderingContext2D::prepare_text(By
|
|||
Gfx::FloatPoint anchor { 0, 0 };
|
||||
auto physical_alignment = Gfx::TextAlignment::CenterLeft;
|
||||
|
||||
auto glyph_run = adopt_ref(*new Gfx::GlyphRun({}, *font, Gfx::GlyphRun::TextType::Ltr));
|
||||
float glyph_run_width = 0;
|
||||
Gfx::for_each_glyph_position(
|
||||
anchor, replaced_text.code_points(), *font, [&](Gfx::DrawGlyph const& glyph) {
|
||||
glyph_run->append(glyph);
|
||||
},
|
||||
glyph_run_width);
|
||||
auto glyph_run = Gfx::shape_text(anchor, replaced_text.code_points(), *font, Gfx::GlyphRun::TextType::Ltr);
|
||||
|
||||
// 8. Let result be an array constructed by iterating over each glyph in the inline box from left to right (if any), adding to the array, for each glyph, the shape of the glyph as it is in the inline box, positioned on a coordinate space using CSS pixels with its origin is at the anchor point.
|
||||
PreparedText prepared_text { glyph_run, physical_alignment, { 0, 0, static_cast<int>(glyph_run_width), static_cast<int>(height) } };
|
||||
PreparedText prepared_text { glyph_run, physical_alignment, { 0, 0, static_cast<int>(glyph_run->width()), static_cast<int>(height) } };
|
||||
|
||||
// 9. Return result, physical alignment, and the inline box.
|
||||
return prepared_text;
|
||||
|
|
|
@ -239,15 +239,8 @@ Optional<InlineLevelIterator::Item> InlineLevelIterator::next_without_lookahead(
|
|||
};
|
||||
}
|
||||
|
||||
Vector<Gfx::DrawGlyph> glyph_run;
|
||||
float glyph_run_width = 0;
|
||||
Gfx::for_each_glyph_position(
|
||||
{ 0, 0 }, chunk.view, chunk.font, [&](Gfx::DrawGlyph const& glyph) {
|
||||
glyph_run.append(glyph);
|
||||
},
|
||||
glyph_run_width);
|
||||
|
||||
CSSPixels chunk_width = CSSPixels::nearest_value_for(glyph_run_width);
|
||||
auto glyph_run = Gfx::shape_text({ 0, 0 }, chunk.view, chunk.font, text_type);
|
||||
CSSPixels chunk_width = CSSPixels::nearest_value_for(glyph_run->width());
|
||||
|
||||
// NOTE: We never consider `content: ""` to be collapsible whitespace.
|
||||
bool is_generated_empty_string = text_node.is_generated() && chunk.length == 0;
|
||||
|
@ -255,7 +248,7 @@ Optional<InlineLevelIterator::Item> InlineLevelIterator::next_without_lookahead(
|
|||
Item item {
|
||||
.type = Item::Type::Text,
|
||||
.node = &text_node,
|
||||
.glyph_run = adopt_ref(*new Gfx::GlyphRun(move(glyph_run), chunk.font, text_type)),
|
||||
.glyph_run = move(glyph_run),
|
||||
.offset_in_node = chunk.start,
|
||||
.length_in_node = chunk.length,
|
||||
.width = chunk_width,
|
||||
|
|
|
@ -233,21 +233,14 @@ void DisplayListRecorder::draw_text(Gfx::IntRect const& rect, String raw_text, G
|
|||
if (rect.is_empty())
|
||||
return;
|
||||
|
||||
auto glyph_run = adopt_ref(*new Gfx::GlyphRun({}, font, Gfx::GlyphRun::TextType::Ltr));
|
||||
float glyph_run_width = 0;
|
||||
Gfx::for_each_glyph_position(
|
||||
{ 0, 0 }, raw_text.code_points(), font, [&](Gfx::DrawGlyph const& glyph) {
|
||||
glyph_run->append(glyph);
|
||||
},
|
||||
glyph_run_width);
|
||||
|
||||
auto glyph_run = Gfx::shape_text({}, raw_text.code_points(), font, Gfx::GlyphRun::TextType::Ltr);
|
||||
float baseline_x = 0;
|
||||
if (alignment == Gfx::TextAlignment::CenterLeft) {
|
||||
baseline_x = rect.x();
|
||||
} else if (alignment == Gfx::TextAlignment::Center) {
|
||||
baseline_x = static_cast<float>(rect.x()) + (static_cast<float>(rect.width()) - glyph_run_width) / 2.0f;
|
||||
baseline_x = static_cast<float>(rect.x()) + (static_cast<float>(rect.width()) - glyph_run->width()) / 2.0f;
|
||||
} else if (alignment == Gfx::TextAlignment::CenterRight) {
|
||||
baseline_x = static_cast<float>(rect.right()) - glyph_run_width;
|
||||
baseline_x = static_cast<float>(rect.right()) - glyph_run->width();
|
||||
} else {
|
||||
// Unimplemented alignment.
|
||||
TODO();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue