LibGfx+LibWeb: Update for_each_glyph_position to use font cascade list

This change updates function that builds list of glyphs to use font
cascade list to find font for each code point.
This commit is contained in:
Aliaksandr Kalenik 2023-12-09 23:45:57 +01:00 committed by Andreas Kling
parent 2cb0039a13
commit df57d7ca68
8 changed files with 66 additions and 16 deletions

Binary file not shown.

View file

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<style>
@font-face {
font-family: 'HashFont';
src: url('../assets/HashSans.woff');
}
.hash-font {
font-family: 'HashFont';
}
.text {
font-size: 100px;
font-family: "SerenitySans";
}
</style>
</head>
<body>
<div class="text"><span class="hash-font">A</span>B</div>
</body>
</html>

View file

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<link rel="match" href="reference/unicode-range-ref.html" />
<style>
@font-face {
font-family: 'HashFont';
src: url('assets/HashSans.woff');
unicode-range: U+0041; /* Only letter 'A' */
}
.text {
font-family: 'HashFont', 'SerenitySans';
font-size: 100px;
}
</style>
</head>
<body>
<div class="text">AB</div>
</body>
</html>

View file

@ -2439,7 +2439,9 @@ void Painter::draw_text_run(IntPoint baseline_start, Utf8View const& string, Fon
void Painter::draw_text_run(FloatPoint baseline_start, Utf8View const& string, Font const& font, Color color)
{
for_each_glyph_position(baseline_start, string, font, [&](DrawGlyphOrEmoji glyph_or_emoji) {
auto font_list = Gfx::FontCascadeList::create();
font_list->add(font);
for_each_glyph_position(baseline_start, string, font_list, [&](DrawGlyphOrEmoji glyph_or_emoji) {
if (glyph_or_emoji.has<DrawGlyph>()) {
auto& glyph = glyph_or_emoji.get<DrawGlyph>();
draw_glyph(glyph.position, glyph.code_point, *glyph.font, color);

View file

@ -170,8 +170,10 @@ void Path::text(Utf8View text, Font const& font)
}
auto& scaled_font = static_cast<ScaledFont const&>(font);
auto font_list = Gfx::FontCascadeList::create();
font_list->add(scaled_font);
for_each_glyph_position(
last_point(), text, font, [&](DrawGlyphOrEmoji glyph_or_emoji) {
last_point(), text, font_list, [&](DrawGlyphOrEmoji glyph_or_emoji) {
if (glyph_or_emoji.has<DrawGlyph>()) {
auto& glyph = glyph_or_emoji.get<DrawGlyph>();
move_to(glyph.position);

View file

@ -14,6 +14,7 @@
#include <AK/Utf8View.h>
#include <AK/Vector.h>
#include <LibGfx/Font/Font.h>
#include <LibGfx/FontCascadeList.h>
#include <LibGfx/Forward.h>
#include <LibGfx/Rect.h>
#include <LibGfx/TextElision.h>
@ -92,34 +93,35 @@ using DrawGlyphOrEmoji = Variant<DrawGlyph, DrawEmoji>;
Variant<DrawGlyph, DrawEmoji> prepare_draw_glyph_or_emoji(FloatPoint point, Utf8CodePointIterator& it, Font const& font);
template<typename Callback>
void for_each_glyph_position(FloatPoint baseline_start, Utf8View string, Font const& font, Callback callback, IncludeLeftBearing include_left_bearing = IncludeLeftBearing::No, Optional<float&> width = {})
void for_each_glyph_position(FloatPoint baseline_start, Utf8View string, FontCascadeList const& font_list, Callback callback, IncludeLeftBearing include_left_bearing = IncludeLeftBearing::No, Optional<float&> width = {})
{
float space_width = font.glyph_width(' ') + font.glyph_spacing();
float space_width = font_list.first().glyph_width(' ') + font_list.first().glyph_spacing();
u32 last_code_point = 0;
auto point = baseline_start;
point.translate_by(0, -font.pixel_metrics().ascent);
for (auto code_point_iterator = string.begin(); code_point_iterator != string.end(); ++code_point_iterator) {
auto it = code_point_iterator; // The callback function will advance the iterator, so create a copy for this lookup.
auto code_point = *code_point_iterator;
RefPtr<Gfx::Font const> font = font_list.font_for_code_point(code_point);
point.set_y(baseline_start.y() - font->pixel_metrics().ascent);
if (should_paint_as_space(code_point)) {
point.translate_by(space_width, 0);
last_code_point = code_point;
continue;
}
auto kerning = font.glyphs_horizontal_kerning(last_code_point, code_point);
auto kerning = font->glyphs_horizontal_kerning(last_code_point, code_point);
if (kerning != 0.0f)
point.translate_by(kerning, 0);
auto it = code_point_iterator; // The callback function will advance the iterator, so create a copy for this lookup.
auto glyph_width = font.glyph_or_emoji_width(it) + font.glyph_spacing();
auto glyph_or_emoji = prepare_draw_glyph_or_emoji(point, code_point_iterator, font);
auto glyph_width = font->glyph_or_emoji_width(it) + font->glyph_spacing();
auto glyph_or_emoji = prepare_draw_glyph_or_emoji(point, code_point_iterator, *font);
if (include_left_bearing == IncludeLeftBearing::Yes) {
if (glyph_or_emoji.has<DrawGlyph>())
glyph_or_emoji.get<DrawGlyph>().position += FloatPoint(font.glyph_left_bearing(code_point), 0);
glyph_or_emoji.get<DrawGlyph>().position += FloatPoint(font->glyph_left_bearing(code_point), 0);
}
callback(glyph_or_emoji);
@ -129,7 +131,7 @@ void for_each_glyph_position(FloatPoint baseline_start, Utf8View string, Font co
}
if (width.has_value())
*width = point.x() - font.glyph_spacing();
*width = point.x() - font_list.first().glyph_spacing();
}
}

View file

@ -190,7 +190,7 @@ Optional<InlineLevelIterator::Item> InlineLevelIterator::next_without_lookahead(
Vector<Gfx::DrawGlyphOrEmoji> glyph_run;
float glyph_run_width = 0;
Gfx::for_each_glyph_position(
{ 0, 0 }, chunk.view, text_node.first_available_font(), [&](Gfx::DrawGlyphOrEmoji const& glyph_or_emoji) {
{ 0, 0 }, chunk.view, text_node.font_list(), [&](Gfx::DrawGlyphOrEmoji const& glyph_or_emoji) {
glyph_run.append(glyph_or_emoji);
return IterationDecision::Continue;
},

View file

@ -638,12 +638,12 @@ static void paint_text_fragment(PaintContext& context, Layout::TextNode const& t
auto text = text_node.text_for_rendering();
DevicePixelPoint baseline_start { fragment_absolute_device_rect.x(), fragment_absolute_device_rect.y() + context.rounded_device_pixels(fragment.baseline()) };
auto const& scaled_font = fragment.layout_node().scaled_font(context);
Vector<Gfx::DrawGlyphOrEmoji> scaled_glyph_run;
scaled_glyph_run.ensure_capacity(fragment.glyph_run().size());
auto& font_cache = text_node.document().style_computer().font_cache();
for (auto glyph : fragment.glyph_run()) {
glyph.visit([&](auto& glyph) {
glyph.font = scaled_font;
glyph.font = font_cache.scaled_font(*glyph.font, context.device_pixels_per_css_pixel());
glyph.position = glyph.position.scaled(context.device_pixels_per_css_pixel());
});
scaled_glyph_run.append(move(glyph));