LibWeb: Store FontCascadeList instead of Font in CanvasState

This is required to implement per-glyph font fallbacks in the upcoming
changes.
This commit is contained in:
Aliaksandr Kalenik 2025-04-19 18:34:53 +02:00 committed by Andreas Kling
parent 455700d379
commit 2c64c6d773
Notes: github-actions[bot] 2025-04-21 07:52:30 +00:00
4 changed files with 22 additions and 20 deletions

View file

@ -231,11 +231,12 @@ Gfx::Path CanvasRenderingContext2D::text_path(StringView text, float x, float y,
return {};
auto& drawing_state = this->drawing_state();
auto font = current_font();
auto const& font = font_cascade_list()->first();
Gfx::Path path;
path.move_to({ x, y });
path.text(Utf8View { text }, *font);
path.text(Utf8View { text }, font);
auto text_width = path.bounding_box().width();
Gfx::AffineTransform transform = {};
@ -268,10 +269,10 @@ Gfx::Path CanvasRenderingContext2D::text_path(StringView text, float x, float y,
// https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-textbaseline-hanging
// Default baseline of draw_text is top so do nothing by CanvasTextBaseline::Top and CanvasTextBaseline::Hanging
if (drawing_state.text_baseline == Bindings::CanvasTextBaseline::Middle) {
transform = Gfx::AffineTransform {}.set_translation({ 0, font->pixel_size() / 2 }).multiply(transform);
transform = Gfx::AffineTransform {}.set_translation({ 0, font.pixel_size() / 2 }).multiply(transform);
}
if (drawing_state.text_baseline == Bindings::CanvasTextBaseline::Top || drawing_state.text_baseline == Bindings::CanvasTextBaseline::Hanging) {
transform = Gfx::AffineTransform {}.set_translation({ 0, font->pixel_size() }).multiply(transform);
transform = Gfx::AffineTransform {}.set_translation({ 0, font.pixel_size() }).multiply(transform);
}
return path.copy_transformed(transform);
@ -530,7 +531,7 @@ GC::Ref<TextMetrics> CanvasRenderingContext2D::measure_text(StringView text)
auto prepared_text = prepare_text(text);
auto metrics = TextMetrics::create(realm());
// FIXME: Use the font that was used to create the glyphs in prepared_text.
auto font = current_font();
auto const& font = font_cascade_list()->first();
// width attribute: The width of that inline box, in CSS pixels. (The text's advance width.)
metrics->set_width(prepared_text.bounding_box.width());
@ -539,19 +540,19 @@ GC::Ref<TextMetrics> CanvasRenderingContext2D::measure_text(StringView text)
// actualBoundingBoxRight attribute: The distance parallel to the baseline from the alignment point given by the textAlign attribute to the right side of the bounding rectangle of the given text, in CSS pixels; positive numbers indicating a distance going right from the given alignment point.
metrics->set_actual_bounding_box_right(prepared_text.bounding_box.right());
// fontBoundingBoxAscent attribute: The distance from the horizontal line indicated by the textBaseline attribute to the ascent metric of the first available font, in CSS pixels; positive numbers indicating a distance going up from the given baseline.
metrics->set_font_bounding_box_ascent(font->baseline());
metrics->set_font_bounding_box_ascent(font.baseline());
// fontBoundingBoxDescent attribute: The distance from the horizontal line indicated by the textBaseline attribute to the descent metric of the first available font, in CSS pixels; positive numbers indicating a distance going down from the given baseline.
metrics->set_font_bounding_box_descent(prepared_text.bounding_box.height() - font->baseline());
metrics->set_font_bounding_box_descent(prepared_text.bounding_box.height() - font.baseline());
// actualBoundingBoxAscent attribute: The distance from the horizontal line indicated by the textBaseline attribute to the top of the bounding rectangle of the given text, in CSS pixels; positive numbers indicating a distance going up from the given baseline.
metrics->set_actual_bounding_box_ascent(font->baseline());
metrics->set_actual_bounding_box_ascent(font.baseline());
// actualBoundingBoxDescent attribute: The distance from the horizontal line indicated by the textBaseline attribute to the bottom of the bounding rectangle of the given text, in CSS pixels; positive numbers indicating a distance going down from the given baseline.
metrics->set_actual_bounding_box_descent(prepared_text.bounding_box.height() - font->baseline());
metrics->set_actual_bounding_box_descent(prepared_text.bounding_box.height() - font.baseline());
// emHeightAscent attribute: The distance from the horizontal line indicated by the textBaseline attribute to the highest top of the em squares in the inline box, in CSS pixels; positive numbers indicating that the given baseline is below the top of that em square (so this value will usually be positive). Zero if the given baseline is the top of that em square; half the font size if the given baseline is the middle of that em square.
metrics->set_em_height_ascent(font->baseline());
metrics->set_em_height_ascent(font.baseline());
// emHeightDescent attribute: The distance from the horizontal line indicated by the textBaseline attribute to the lowest bottom of the em squares in the inline box, in CSS pixels; positive numbers indicating that the given baseline is above the bottom of that em square. (Zero if the given baseline is the bottom of that em square.)
metrics->set_em_height_descent(prepared_text.bounding_box.height() - font->baseline());
metrics->set_em_height_descent(prepared_text.bounding_box.height() - font.baseline());
// hangingBaseline attribute: The distance from the horizontal line indicated by the textBaseline attribute to the hanging baseline of the inline box, in CSS pixels; positive numbers indicating that the given baseline is below the hanging baseline. (Zero if the given baseline is the hanging baseline.)
metrics->set_hanging_baseline(font->baseline());
metrics->set_hanging_baseline(font.baseline());
// alphabeticBaseline attribute: The distance from the horizontal line indicated by the textBaseline attribute to the alphabetic baseline of the inline box, in CSS pixels; positive numbers indicating that the given baseline is below the alphabetic baseline. (Zero if the given baseline is the alphabetic baseline.)
metrics->set_font_bounding_box_ascent(0);
// ideographicBaseline attribute: The distance from the horizontal line indicated by the textBaseline attribute to the ideographic-under baseline of the inline box, in CSS pixels; positive numbers indicating that the given baseline is below the ideographic-under baseline. (Zero if the given baseline is the ideographic-under baseline.)
@ -560,7 +561,7 @@ GC::Ref<TextMetrics> CanvasRenderingContext2D::measure_text(StringView text)
return metrics;
}
RefPtr<Gfx::Font const> CanvasRenderingContext2D::current_font()
RefPtr<Gfx::FontCascadeList const> CanvasRenderingContext2D::font_cascade_list()
{
// When font style value is empty load default font
if (!drawing_state().font_style_value) {
@ -568,7 +569,7 @@ RefPtr<Gfx::Font const> CanvasRenderingContext2D::current_font()
}
// Get current loaded font
return drawing_state().current_font;
return drawing_state().current_font_cascade_list;
}
// https://html.spec.whatwg.org/multipage/canvas.html#text-preparation-algorithm
@ -587,7 +588,7 @@ CanvasRenderingContext2D::PreparedText CanvasRenderingContext2D::prepare_text(By
auto replaced_text = MUST(builder.to_string());
// 3. Let font be the current font of target, as given by that object's font attribute.
auto font = current_font();
auto const& font = font_cascade_list()->first();
// FIXME: 4. Let language be the target's language.
// FIXME: 5. If language is "inherit":
@ -611,7 +612,7 @@ CanvasRenderingContext2D::PreparedText CanvasRenderingContext2D::prepare_text(By
// ...and with all other properties set to their initial values.
// FIXME: Actually use a LineBox here instead of, you know, using the default font and measuring its size (which is not the spec at all).
// FIXME: Once we have CanvasTextDrawingStyles, add the CSS attributes.
size_t height = font->pixel_size();
size_t height = font.pixel_size();
// 9. If maxWidth was provided and the hypothetical width of the inline box in the hypothetical line box is greater than maxWidth CSS pixels, then change font to have a more condensed font (if one is available or if a reasonably readable one can be synthesized by applying a horizontal scale factor to the font) or a smaller font, and return to the previous step.
// FIXME: Record the font size used for this piece of text, and actually retry with a smaller size if needed.
@ -622,7 +623,7 @@ CanvasRenderingContext2D::PreparedText CanvasRenderingContext2D::prepare_text(By
Gfx::FloatPoint anchor { 0, 0 };
auto physical_alignment = Gfx::TextAlignment::CenterLeft;
auto glyph_run = Gfx::shape_text(anchor, 0, replaced_text.code_points(), *font, Gfx::GlyphRun::TextType::Ltr, {});
auto glyph_run = Gfx::shape_text(anchor, 0, replaced_text.code_points(), font, Gfx::GlyphRun::TextType::Ltr, {});
// 11. 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