mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-12-07 21:59:54 +00:00
LibWeb: Factor out some class template methods into implementation files
Reduces the rebuild required for changes to the .cpp parts (or their includes)
This commit is contained in:
parent
2a68087dfc
commit
64f438857b
Notes:
github-actions[bot]
2025-10-27 14:52:38 +00:00
Author: https://github.com/Calme1709
Commit: 64f438857b
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6576
Reviewed-by: https://github.com/AtkinsSJ ✅
8 changed files with 425 additions and 303 deletions
|
|
@ -434,9 +434,11 @@ set(SOURCES
|
|||
HTML/BrowsingContext.cpp
|
||||
HTML/BrowsingContextGroup.cpp
|
||||
HTML/Canvas/CanvasDrawImage.cpp
|
||||
HTML/Canvas/CanvasFillStrokeStyles.cpp
|
||||
HTML/Canvas/CanvasPath.cpp
|
||||
HTML/Canvas/CanvasSettings.cpp
|
||||
HTML/Canvas/CanvasState.cpp
|
||||
HTML/Canvas/CanvasTextDrawingStyles.cpp
|
||||
HTML/Canvas/SerializeBitmap.cpp
|
||||
HTML/CanvasGradient.cpp
|
||||
HTML/CanvasPattern.cpp
|
||||
|
|
@ -921,6 +923,7 @@ set(SOURCES
|
|||
SVG/SVGFEMergeNodeElement.cpp
|
||||
SVG/SVGFEOffsetElement.cpp
|
||||
SVG/SVGFilterElement.cpp
|
||||
SVG/SVGFilterPrimitiveStandardAttributes.cpp
|
||||
SVG/SVGFitToViewBox.cpp
|
||||
SVG/SVGForeignObjectElement.cpp
|
||||
SVG/SVGGElement.cpp
|
||||
|
|
|
|||
176
Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.cpp
Normal file
176
Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.cpp
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022, Andreas Kling <andreas@ladybird.org>
|
||||
* Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
|
||||
* Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
|
||||
* Copyright (c) 2023, MacDue <macdue@dueutil.tech>
|
||||
* Copyright (c) 2025, Callum Law <callumlaw1709@outlook.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "CanvasFillStrokeStyles.h"
|
||||
#include <AK/String.h>
|
||||
#include <LibWeb/CSS/Parser/Parser.h>
|
||||
#include <LibWeb/HTML/CanvasGradient.h>
|
||||
#include <LibWeb/HTML/CanvasPattern.h>
|
||||
#include <LibWeb/HTML/CanvasRenderingContext2D.h>
|
||||
#include <LibWeb/HTML/HTMLCanvasElement.h>
|
||||
#include <LibWeb/HTML/OffscreenCanvasRenderingContext2D.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
||||
template<typename IncludingClass>
|
||||
void CanvasFillStrokeStyles<IncludingClass>::set_fill_style(FillOrStrokeStyleVariant style)
|
||||
{
|
||||
// https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-fillstyle
|
||||
style.visit(
|
||||
// 1. If the given value is a string, then:
|
||||
[&](String const& string) {
|
||||
// 1. Let context be this's canvas attribute's value, if that is an element; otherwise null.
|
||||
HTMLCanvasElement* context = my_canvas_element().visit(
|
||||
[&](HTMLCanvasElement* canvas_element) -> HTMLCanvasElement* {
|
||||
return canvas_element;
|
||||
},
|
||||
[&](OffscreenCanvas*) -> HTMLCanvasElement* {
|
||||
return nullptr;
|
||||
});
|
||||
|
||||
// 2. Let parsedValue be the result of parsing the given value with context if non-null.
|
||||
// FIXME: Parse a color value
|
||||
// https://drafts.csswg.org/css-color/#parse-a-css-color-value
|
||||
auto style_value = parse_css_value(CSS::Parser::ParsingParams(), string, CSS::PropertyID::Color);
|
||||
if (style_value && style_value->has_color()) {
|
||||
CSS::ColorResolutionContext color_resolution_context {};
|
||||
|
||||
if (context && context->layout_node()) {
|
||||
color_resolution_context = CSS::ColorResolutionContext::for_layout_node_with_style(*context->layout_node());
|
||||
}
|
||||
|
||||
auto parsedValue = style_value->to_color(color_resolution_context).value_or(Color::Black);
|
||||
|
||||
// 4. Set this's fill style to parsedValue.
|
||||
my_drawing_state().fill_style = parsedValue;
|
||||
} else {
|
||||
// 3. If parsedValue is failure, then return.
|
||||
return;
|
||||
}
|
||||
|
||||
// 5. Return.
|
||||
return;
|
||||
},
|
||||
[&](auto fill_or_stroke_style) {
|
||||
// FIXME: 2. If the given value is a CanvasPattern object that is marked as not origin-clean, then set this's origin-clean flag to false.
|
||||
|
||||
// 3. Set this's fill style to the given value.
|
||||
my_drawing_state().fill_style = fill_or_stroke_style;
|
||||
});
|
||||
}
|
||||
|
||||
template<typename IncludingClass>
|
||||
CanvasFillStrokeStyles<IncludingClass>::FillOrStrokeStyleVariant CanvasFillStrokeStyles<IncludingClass>::fill_style() const
|
||||
{
|
||||
return my_drawing_state().fill_style.to_js_fill_or_stroke_style();
|
||||
}
|
||||
|
||||
template<typename IncludingClass>
|
||||
void CanvasFillStrokeStyles<IncludingClass>::set_stroke_style(FillOrStrokeStyleVariant style)
|
||||
{
|
||||
// https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-strokestyle
|
||||
|
||||
style.visit(
|
||||
// 1. If the given value is a string, then:
|
||||
[&](String const& string) {
|
||||
// 1. Let context be this's canvas attribute's value, if that is an element; otherwise null.
|
||||
HTMLCanvasElement* context = my_canvas_element().visit(
|
||||
[&](HTMLCanvasElement* canvas_element) -> HTMLCanvasElement* {
|
||||
return canvas_element;
|
||||
},
|
||||
[&](OffscreenCanvas*) -> HTMLCanvasElement* {
|
||||
return nullptr;
|
||||
});
|
||||
|
||||
// 2. Let parsedValue be the result of parsing the given value with context if non-null.
|
||||
// FIXME: Parse a color value
|
||||
// https://drafts.csswg.org/css-color/#parse-a-css-color-value
|
||||
auto style_value = parse_css_value(CSS::Parser::ParsingParams(), string, CSS::PropertyID::Color);
|
||||
if (style_value && style_value->has_color()) {
|
||||
CSS::ColorResolutionContext color_resolution_context {};
|
||||
|
||||
if (context && context->layout_node()) {
|
||||
color_resolution_context = CSS::ColorResolutionContext::for_layout_node_with_style(*context->layout_node());
|
||||
}
|
||||
|
||||
auto parsedValue = style_value->to_color(color_resolution_context).value_or(Color::Black);
|
||||
|
||||
// 4. Set this's stroke style to parsedValue.
|
||||
my_drawing_state().stroke_style = parsedValue;
|
||||
} else {
|
||||
// 3. If parsedValue is failure, then return.
|
||||
return;
|
||||
}
|
||||
|
||||
// 5. Return.
|
||||
return;
|
||||
},
|
||||
[&](auto fill_or_stroke_style) {
|
||||
// FIXME: 2. If the given value is a CanvasPattern object that is marked as not origin-clean, then set this's origin-clean flag to false.
|
||||
|
||||
// 3. Set this's stroke style to the given value.
|
||||
my_drawing_state().fill_style = fill_or_stroke_style;
|
||||
});
|
||||
}
|
||||
|
||||
template<typename IncludingClass>
|
||||
CanvasFillStrokeStyles<IncludingClass>::FillOrStrokeStyleVariant CanvasFillStrokeStyles<IncludingClass>::stroke_style() const
|
||||
{
|
||||
return my_drawing_state().stroke_style.to_js_fill_or_stroke_style();
|
||||
}
|
||||
template<typename IncludingClass>
|
||||
Variant<HTMLCanvasElement*, OffscreenCanvas*> CanvasFillStrokeStyles<IncludingClass>::my_canvas_element()
|
||||
{
|
||||
return &reinterpret_cast<IncludingClass&>(*this).canvas_element();
|
||||
}
|
||||
|
||||
template<typename IncludingClass>
|
||||
CanvasState::DrawingState& CanvasFillStrokeStyles<IncludingClass>::my_drawing_state()
|
||||
{
|
||||
return reinterpret_cast<IncludingClass&>(*this).drawing_state();
|
||||
}
|
||||
|
||||
template<typename IncludingClass>
|
||||
CanvasState::DrawingState const& CanvasFillStrokeStyles<IncludingClass>::my_drawing_state() const
|
||||
{
|
||||
return reinterpret_cast<IncludingClass const&>(*this).drawing_state();
|
||||
}
|
||||
|
||||
template<typename IncludingClass>
|
||||
WebIDL::ExceptionOr<GC::Ref<CanvasGradient>> CanvasFillStrokeStyles<IncludingClass>::create_radial_gradient(double x0, double y0, double r0, double x1, double y1, double r1)
|
||||
{
|
||||
auto& realm = static_cast<IncludingClass&>(*this).realm();
|
||||
return CanvasGradient::create_radial(realm, x0, y0, r0, x1, y1, r1);
|
||||
}
|
||||
template<typename IncludingClass>
|
||||
GC::Ref<CanvasGradient> CanvasFillStrokeStyles<IncludingClass>::create_linear_gradient(double x0, double y0, double x1, double y1)
|
||||
{
|
||||
auto& realm = static_cast<IncludingClass&>(*this).realm();
|
||||
return CanvasGradient::create_linear(realm, x0, y0, x1, y1).release_value_but_fixme_should_propagate_errors();
|
||||
}
|
||||
|
||||
template<typename IncludingClass>
|
||||
GC::Ref<CanvasGradient> CanvasFillStrokeStyles<IncludingClass>::create_conic_gradient(double start_angle, double x, double y)
|
||||
{
|
||||
auto& realm = static_cast<IncludingClass&>(*this).realm();
|
||||
return CanvasGradient::create_conic(realm, start_angle, x, y).release_value_but_fixme_should_propagate_errors();
|
||||
}
|
||||
|
||||
template<typename IncludingClass>
|
||||
WebIDL::ExceptionOr<GC::Ptr<CanvasPattern>> CanvasFillStrokeStyles<IncludingClass>::create_pattern(CanvasImageSource const& image, StringView repetition)
|
||||
{
|
||||
auto& realm = static_cast<IncludingClass&>(*this).realm();
|
||||
return CanvasPattern::create(realm, image, repetition);
|
||||
}
|
||||
|
||||
template class CanvasFillStrokeStyles<CanvasRenderingContext2D>;
|
||||
template class CanvasFillStrokeStyles<OffscreenCanvasRenderingContext2D>;
|
||||
|
||||
}
|
||||
|
|
@ -9,13 +9,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <LibWeb/CSS/Parser/Parser.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/HTML/Canvas/CanvasState.h>
|
||||
#include <LibWeb/HTML/CanvasGradient.h>
|
||||
#include <LibWeb/HTML/CanvasPattern.h>
|
||||
#include <LibWeb/HTML/HTMLCanvasElement.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
||||
|
|
@ -26,140 +21,24 @@ public:
|
|||
~CanvasFillStrokeStyles() = default;
|
||||
using FillOrStrokeStyleVariant = Variant<String, GC::Root<CanvasGradient>, GC::Root<CanvasPattern>>;
|
||||
|
||||
void set_fill_style(FillOrStrokeStyleVariant style)
|
||||
{
|
||||
// https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-fillstyle
|
||||
style.visit(
|
||||
// 1. If the given value is a string, then:
|
||||
[&](String const& string) {
|
||||
// 1. Let context be this's canvas attribute's value, if that is an element; otherwise null.
|
||||
HTMLCanvasElement* context = my_canvas_element().visit(
|
||||
[&](HTMLCanvasElement* canvas_element) -> HTMLCanvasElement* {
|
||||
return canvas_element;
|
||||
},
|
||||
[&](OffscreenCanvas*) -> HTMLCanvasElement* {
|
||||
return nullptr;
|
||||
});
|
||||
void set_fill_style(FillOrStrokeStyleVariant style);
|
||||
FillOrStrokeStyleVariant fill_style() const;
|
||||
|
||||
// 2. Let parsedValue be the result of parsing the given value with context if non-null.
|
||||
// FIXME: Parse a color value
|
||||
// https://drafts.csswg.org/css-color/#parse-a-css-color-value
|
||||
auto style_value = parse_css_value(CSS::Parser::ParsingParams(), string, CSS::PropertyID::Color);
|
||||
if (style_value && style_value->has_color()) {
|
||||
CSS::ColorResolutionContext color_resolution_context {};
|
||||
void set_stroke_style(FillOrStrokeStyleVariant style);
|
||||
FillOrStrokeStyleVariant stroke_style() const;
|
||||
|
||||
if (context && context->layout_node()) {
|
||||
color_resolution_context = CSS::ColorResolutionContext::for_layout_node_with_style(*context->layout_node());
|
||||
}
|
||||
|
||||
auto parsedValue = style_value->to_color(color_resolution_context).value_or(Color::Black);
|
||||
|
||||
// 4. Set this's fill style to parsedValue.
|
||||
my_drawing_state().fill_style = parsedValue;
|
||||
} else {
|
||||
// 3. If parsedValue is failure, then return.
|
||||
return;
|
||||
}
|
||||
|
||||
// 5. Return.
|
||||
return;
|
||||
},
|
||||
[&](auto fill_or_stroke_style) {
|
||||
// FIXME: 2. If the given value is a CanvasPattern object that is marked as not origin-clean, then set this's origin-clean flag to false.
|
||||
|
||||
// 3. Set this's fill style to the given value.
|
||||
my_drawing_state().fill_style = fill_or_stroke_style;
|
||||
});
|
||||
}
|
||||
|
||||
FillOrStrokeStyleVariant fill_style() const
|
||||
{
|
||||
return my_drawing_state().fill_style.to_js_fill_or_stroke_style();
|
||||
}
|
||||
|
||||
void set_stroke_style(FillOrStrokeStyleVariant style)
|
||||
{
|
||||
// https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-strokestyle
|
||||
|
||||
style.visit(
|
||||
// 1. If the given value is a string, then:
|
||||
[&](String const& string) {
|
||||
// 1. Let context be this's canvas attribute's value, if that is an element; otherwise null.
|
||||
HTMLCanvasElement* context = my_canvas_element().visit(
|
||||
[&](HTMLCanvasElement* canvas_element) -> HTMLCanvasElement* {
|
||||
return canvas_element;
|
||||
},
|
||||
[&](OffscreenCanvas*) -> HTMLCanvasElement* {
|
||||
return nullptr;
|
||||
});
|
||||
|
||||
// 2. Let parsedValue be the result of parsing the given value with context if non-null.
|
||||
// FIXME: Parse a color value
|
||||
// https://drafts.csswg.org/css-color/#parse-a-css-color-value
|
||||
auto style_value = parse_css_value(CSS::Parser::ParsingParams(), string, CSS::PropertyID::Color);
|
||||
if (style_value && style_value->has_color()) {
|
||||
CSS::ColorResolutionContext color_resolution_context {};
|
||||
|
||||
if (context && context->layout_node()) {
|
||||
color_resolution_context = CSS::ColorResolutionContext::for_layout_node_with_style(*context->layout_node());
|
||||
}
|
||||
|
||||
auto parsedValue = style_value->to_color(color_resolution_context).value_or(Color::Black);
|
||||
|
||||
// 4. Set this's stroke style to parsedValue.
|
||||
my_drawing_state().stroke_style = parsedValue;
|
||||
} else {
|
||||
// 3. If parsedValue is failure, then return.
|
||||
return;
|
||||
}
|
||||
|
||||
// 5. Return.
|
||||
return;
|
||||
},
|
||||
[&](auto fill_or_stroke_style) {
|
||||
// FIXME: 2. If the given value is a CanvasPattern object that is marked as not origin-clean, then set this's origin-clean flag to false.
|
||||
|
||||
// 3. Set this's stroke style to the given value.
|
||||
my_drawing_state().fill_style = fill_or_stroke_style;
|
||||
});
|
||||
}
|
||||
|
||||
FillOrStrokeStyleVariant stroke_style() const
|
||||
{
|
||||
return my_drawing_state().stroke_style.to_js_fill_or_stroke_style();
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<GC::Ref<CanvasGradient>> create_radial_gradient(double x0, double y0, double r0, double x1, double y1, double r1)
|
||||
{
|
||||
auto& realm = static_cast<IncludingClass&>(*this).realm();
|
||||
return CanvasGradient::create_radial(realm, x0, y0, r0, x1, y1, r1);
|
||||
}
|
||||
|
||||
GC::Ref<CanvasGradient> create_linear_gradient(double x0, double y0, double x1, double y1)
|
||||
{
|
||||
auto& realm = static_cast<IncludingClass&>(*this).realm();
|
||||
return CanvasGradient::create_linear(realm, x0, y0, x1, y1).release_value_but_fixme_should_propagate_errors();
|
||||
}
|
||||
|
||||
GC::Ref<CanvasGradient> create_conic_gradient(double start_angle, double x, double y)
|
||||
{
|
||||
auto& realm = static_cast<IncludingClass&>(*this).realm();
|
||||
return CanvasGradient::create_conic(realm, start_angle, x, y).release_value_but_fixme_should_propagate_errors();
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<GC::Ptr<CanvasPattern>> create_pattern(CanvasImageSource const& image, StringView repetition)
|
||||
{
|
||||
auto& realm = static_cast<IncludingClass&>(*this).realm();
|
||||
return CanvasPattern::create(realm, image, repetition);
|
||||
}
|
||||
WebIDL::ExceptionOr<GC::Ref<CanvasGradient>> create_radial_gradient(double x0, double y0, double r0, double x1, double y1, double r1);
|
||||
GC::Ref<CanvasGradient> create_linear_gradient(double x0, double y0, double x1, double y1);
|
||||
GC::Ref<CanvasGradient> create_conic_gradient(double start_angle, double x, double y);
|
||||
WebIDL::ExceptionOr<GC::Ptr<CanvasPattern>> create_pattern(CanvasImageSource const& image, StringView repetition);
|
||||
|
||||
protected:
|
||||
CanvasFillStrokeStyles() = default;
|
||||
|
||||
private:
|
||||
Variant<HTMLCanvasElement*, OffscreenCanvas*> my_canvas_element() { return &reinterpret_cast<IncludingClass&>(*this).canvas_element(); }
|
||||
CanvasState::DrawingState& my_drawing_state() { return reinterpret_cast<IncludingClass&>(*this).drawing_state(); }
|
||||
CanvasState::DrawingState const& my_drawing_state() const { return reinterpret_cast<IncludingClass const&>(*this).drawing_state(); }
|
||||
Variant<HTMLCanvasElement*, OffscreenCanvas*> my_canvas_element();
|
||||
CanvasState::DrawingState& my_drawing_state();
|
||||
CanvasState::DrawingState const& my_drawing_state() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
164
Libraries/LibWeb/HTML/Canvas/CanvasTextDrawingStyles.cpp
Normal file
164
Libraries/LibWeb/HTML/Canvas/CanvasTextDrawingStyles.cpp
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Bastiaan van der Plaat <bastiaan.v.d.plaat@gmail.com>
|
||||
* Copyright (c) 2023, Callum Law <callumlaw1709@outlook.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "CanvasTextDrawingStyles.h"
|
||||
#include <LibWeb/CSS/StyleComputer.h>
|
||||
#include <LibWeb/CSS/StyleValues/FontStyleStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/LengthStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/NumberStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/PercentageStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/ShorthandStyleValue.h>
|
||||
#include <LibWeb/HTML/Canvas/CanvasState.h>
|
||||
#include <LibWeb/HTML/CanvasRenderingContext2D.h>
|
||||
#include <LibWeb/HTML/OffscreenCanvas.h>
|
||||
#include <LibWeb/HTML/OffscreenCanvasRenderingContext2D.h>
|
||||
#include <LibWeb/HTML/Window.h>
|
||||
#include <LibWeb/HTML/WorkerGlobalScope.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
||||
template<typename IncludingClass, typename CanvasType>
|
||||
ByteString CanvasTextDrawingStyles<IncludingClass, CanvasType>::font() const
|
||||
{
|
||||
// When font style value is empty return default string
|
||||
if (!my_drawing_state().font_style_value) {
|
||||
return "10px sans-serif";
|
||||
}
|
||||
|
||||
// On getting, the font attribute must return the serialized form of the current font of the context (with no 'line-height' component).
|
||||
auto const& font_style_value = my_drawing_state().font_style_value->as_shorthand();
|
||||
auto font_style = font_style_value.longhand(CSS::PropertyID::FontStyle);
|
||||
auto font_weight = font_style_value.longhand(CSS::PropertyID::FontWeight);
|
||||
auto font_size = font_style_value.longhand(CSS::PropertyID::FontSize);
|
||||
auto font_family = font_style_value.longhand(CSS::PropertyID::FontFamily);
|
||||
return ByteString::formatted("{} {} {} {}",
|
||||
font_style->to_string(CSS::SerializationMode::Normal),
|
||||
font_weight->to_string(CSS::SerializationMode::Normal),
|
||||
font_size->to_string(CSS::SerializationMode::Normal),
|
||||
font_family->to_string(CSS::SerializationMode::Normal));
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/canvas.html#font-style-source-object
|
||||
template<typename IncludingClass, typename CanvasType>
|
||||
Variant<DOM::Document*, HTML::WorkerGlobalScope*> CanvasTextDrawingStyles<IncludingClass, CanvasType>::get_font_source_for_font_style_source_object(CanvasType& font_style_source_object)
|
||||
{
|
||||
// Font resolution for the font style source object requires a font source. This is determined for a given object implementing CanvasTextDrawingStyles by the following steps: [CSSFONTLOAD]
|
||||
|
||||
if constexpr (SameAs<CanvasType, HTML::HTMLCanvasElement>) {
|
||||
// 1. If object's font style source object is a canvas element, return the element's node document.
|
||||
return &font_style_source_object.document();
|
||||
} else {
|
||||
// 2. Otherwise, object's font style source object is an OffscreenCanvas object:
|
||||
|
||||
// 1. Let global be object's relevant global object.
|
||||
auto& global_object = HTML::relevant_global_object(font_style_source_object);
|
||||
|
||||
// 2. If global is a Window object, then return global's associated Document.
|
||||
if (is<HTML::Window>(global_object)) {
|
||||
auto& window = as<HTML::Window>(global_object);
|
||||
return &(window.associated_document());
|
||||
}
|
||||
|
||||
// 3. Assert: global implements WorkerGlobalScope.
|
||||
VERIFY(is<HTML::WorkerGlobalScope>(global_object));
|
||||
|
||||
// 4. Return global.
|
||||
return &(as<HTML::WorkerGlobalScope>(global_object));
|
||||
};
|
||||
}
|
||||
template<typename IncludingClass, typename CanvasType>
|
||||
void CanvasTextDrawingStyles<IncludingClass, CanvasType>::set_font(StringView font)
|
||||
{
|
||||
// The font IDL attribute, on setting, must be parsed as a CSS <'font'> value (but without supporting property-independent style sheet syntax like 'inherit'),
|
||||
// and the resulting font must be assigned to the context, with the 'line-height' component forced to 'normal', with the 'font-size' component converted to CSS pixels,
|
||||
// and with system fonts being computed to explicit values.
|
||||
// FIXME: with the 'line-height' component forced to 'normal'
|
||||
// FIXME: with the 'font-size' component converted to CSS pixels
|
||||
// FIXME: Disallow tree counting functions if this is an offscreen canvas
|
||||
auto font_style_value_result = parse_css_value(CSS::Parser::ParsingParams {}, font, CSS::PropertyID::Font);
|
||||
|
||||
// If the new value is syntactically incorrect (including using property-independent style sheet syntax like 'inherit' or 'initial'), then it must be ignored, without assigning a new font value.
|
||||
// NOTE: ShorthandStyleValue should be the only valid option here. We implicitly VERIFY this below.
|
||||
if (!font_style_value_result || !font_style_value_result->is_shorthand()) {
|
||||
return;
|
||||
}
|
||||
my_drawing_state().font_style_value = font_style_value_result.release_nonnull();
|
||||
|
||||
// Load font with font style value properties
|
||||
auto const& font_style_value = my_drawing_state().font_style_value->as_shorthand();
|
||||
auto& canvas_element = reinterpret_cast<IncludingClass&>(*this).canvas_element();
|
||||
|
||||
auto& font_style = *font_style_value.longhand(CSS::PropertyID::FontStyle);
|
||||
auto& font_weight = *font_style_value.longhand(CSS::PropertyID::FontWeight);
|
||||
auto& font_width = *font_style_value.longhand(CSS::PropertyID::FontWidth);
|
||||
auto& font_size = *font_style_value.longhand(CSS::PropertyID::FontSize);
|
||||
auto& font_family = *font_style_value.longhand(CSS::PropertyID::FontFamily);
|
||||
|
||||
// https://drafts.csswg.org/css-font-loading/#font-source
|
||||
auto font_source = get_font_source_for_font_style_source_object(canvas_element);
|
||||
|
||||
auto font_list = font_source.visit(
|
||||
[&](DOM::Document* document) -> RefPtr<Gfx::FontCascadeList const> {
|
||||
auto computed_math_depth = CSS::InitialValues::math_depth();
|
||||
auto inherited_math_depth = CSS::InitialValues::math_depth();
|
||||
|
||||
// NOTE: The initial value here is non-standard as the default font is "10px sans-serif"
|
||||
auto inherited_font_size = CSSPixels { 10 };
|
||||
auto inherited_font_weight = CSS::InitialValues::font_weight();
|
||||
// FIXME: Investigate whether this is the correct resolution context (i.e. whether we should instead use
|
||||
// a font-size of 10px) for OffscreenCanvas
|
||||
auto length_resolution_context = CSS::Length::ResolutionContext::for_window(*document->window());
|
||||
Optional<DOM::AbstractElement> abstract_element;
|
||||
|
||||
if constexpr (SameAs<CanvasType, HTML::HTMLCanvasElement>) {
|
||||
// NOTE: The canvas itself is considered the inheritance parent
|
||||
if (canvas_element.computed_properties()) {
|
||||
// NOTE: Since we can't set a math depth directly here we always use the inherited value for the computed value
|
||||
computed_math_depth = canvas_element.computed_properties()->math_depth();
|
||||
inherited_math_depth = canvas_element.computed_properties()->math_depth();
|
||||
inherited_font_size = canvas_element.computed_properties()->font_size();
|
||||
inherited_font_weight = canvas_element.computed_properties()->font_weight();
|
||||
|
||||
abstract_element = DOM::AbstractElement { canvas_element };
|
||||
|
||||
length_resolution_context = CSS::Length::ResolutionContext::for_element(abstract_element.value());
|
||||
}
|
||||
}
|
||||
|
||||
CSS::ComputationContext computation_context {
|
||||
.length_resolution_context = length_resolution_context,
|
||||
.abstract_element = abstract_element
|
||||
};
|
||||
|
||||
// FIXME: Should font be recomputed on canvas element style change?
|
||||
auto const& computed_font_size = CSS::StyleComputer::compute_font_size(font_size, computed_math_depth, inherited_font_size, inherited_math_depth, computation_context);
|
||||
auto const& computed_font_weight = CSS::StyleComputer::compute_font_weight(font_weight, inherited_font_weight, computation_context);
|
||||
auto const& computed_font_width = CSS::StyleComputer::compute_font_width(font_width, computation_context);
|
||||
auto const& computed_font_style = CSS::StyleComputer::compute_font_style(font_style, computation_context);
|
||||
|
||||
return document->style_computer().compute_font_for_style_values(
|
||||
font_family,
|
||||
computed_font_size->as_length().length().absolute_length_to_px(),
|
||||
computed_font_style->as_font_style().to_font_slope(),
|
||||
computed_font_weight->as_number().number(),
|
||||
computed_font_width->as_percentage().percentage());
|
||||
},
|
||||
[](HTML::WorkerGlobalScope*) -> RefPtr<Gfx::FontCascadeList const> {
|
||||
// FIXME: implement computing the font for HTML::WorkerGlobalScope
|
||||
return {};
|
||||
});
|
||||
|
||||
if (!font_list)
|
||||
return;
|
||||
|
||||
my_drawing_state().current_font_cascade_list = font_list;
|
||||
}
|
||||
|
||||
template class CanvasTextDrawingStyles<CanvasRenderingContext2D, HTMLCanvasElement>;
|
||||
template class CanvasTextDrawingStyles<OffscreenCanvasRenderingContext2D, HTML::OffscreenCanvas>;
|
||||
|
||||
}
|
||||
|
|
@ -6,18 +6,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <LibWeb/CSS/Parser/Parser.h>
|
||||
#include <LibWeb/CSS/StyleComputer.h>
|
||||
#include <LibWeb/CSS/StyleValues/FontStyleStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/LengthStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/NumberStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/PercentageStyleValue.h>
|
||||
#include <LibWeb/CSS/StyleValues/ShorthandStyleValue.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/HTML/Canvas/CanvasState.h>
|
||||
#include <LibWeb/HTML/OffscreenCanvas.h>
|
||||
#include <LibWeb/HTML/Window.h>
|
||||
#include <LibWeb/HTML/WorkerGlobalScope.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
||||
|
|
@ -26,141 +15,11 @@ template<typename IncludingClass, typename CanvasType>
|
|||
class CanvasTextDrawingStyles {
|
||||
public:
|
||||
~CanvasTextDrawingStyles() = default;
|
||||
|
||||
ByteString font() const
|
||||
{
|
||||
// When font style value is empty return default string
|
||||
if (!my_drawing_state().font_style_value) {
|
||||
return "10px sans-serif";
|
||||
}
|
||||
|
||||
// On getting, the font attribute must return the serialized form of the current font of the context (with no 'line-height' component).
|
||||
auto const& font_style_value = my_drawing_state().font_style_value->as_shorthand();
|
||||
auto font_style = font_style_value.longhand(CSS::PropertyID::FontStyle);
|
||||
auto font_weight = font_style_value.longhand(CSS::PropertyID::FontWeight);
|
||||
auto font_size = font_style_value.longhand(CSS::PropertyID::FontSize);
|
||||
auto font_family = font_style_value.longhand(CSS::PropertyID::FontFamily);
|
||||
return ByteString::formatted("{} {} {} {}",
|
||||
font_style->to_string(CSS::SerializationMode::Normal),
|
||||
font_weight->to_string(CSS::SerializationMode::Normal),
|
||||
font_size->to_string(CSS::SerializationMode::Normal),
|
||||
font_family->to_string(CSS::SerializationMode::Normal));
|
||||
}
|
||||
ByteString font() const;
|
||||
void set_font(StringView font);
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/canvas.html#font-style-source-object
|
||||
Variant<DOM::Document*, HTML::WorkerGlobalScope*> get_font_source_for_font_style_source_object(CanvasType& font_style_source_object)
|
||||
{
|
||||
// Font resolution for the font style source object requires a font source. This is determined for a given object implementing CanvasTextDrawingStyles by the following steps: [CSSFONTLOAD]
|
||||
|
||||
if constexpr (SameAs<CanvasType, HTML::HTMLCanvasElement>) {
|
||||
// 1. If object's font style source object is a canvas element, return the element's node document.
|
||||
return &font_style_source_object.document();
|
||||
} else {
|
||||
// 2. Otherwise, object's font style source object is an OffscreenCanvas object:
|
||||
|
||||
// 1. Let global be object's relevant global object.
|
||||
auto& global_object = HTML::relevant_global_object(font_style_source_object);
|
||||
|
||||
// 2. If global is a Window object, then return global's associated Document.
|
||||
if (is<HTML::Window>(global_object)) {
|
||||
auto& window = as<HTML::Window>(global_object);
|
||||
return &(window.associated_document());
|
||||
}
|
||||
|
||||
// 3. Assert: global implements WorkerGlobalScope.
|
||||
VERIFY(is<HTML::WorkerGlobalScope>(global_object));
|
||||
|
||||
// 4. Return global.
|
||||
return &(as<HTML::WorkerGlobalScope>(global_object));
|
||||
};
|
||||
}
|
||||
|
||||
void set_font(StringView font)
|
||||
{
|
||||
// The font IDL attribute, on setting, must be parsed as a CSS <'font'> value (but without supporting property-independent style sheet syntax like 'inherit'),
|
||||
// and the resulting font must be assigned to the context, with the 'line-height' component forced to 'normal', with the 'font-size' component converted to CSS pixels,
|
||||
// and with system fonts being computed to explicit values.
|
||||
// FIXME: with the 'line-height' component forced to 'normal'
|
||||
// FIXME: with the 'font-size' component converted to CSS pixels
|
||||
// FIXME: Disallow tree counting functions if this is an offscreen canvas
|
||||
auto font_style_value_result = parse_css_value(CSS::Parser::ParsingParams {}, font, CSS::PropertyID::Font);
|
||||
|
||||
// If the new value is syntactically incorrect (including using property-independent style sheet syntax like 'inherit' or 'initial'), then it must be ignored, without assigning a new font value.
|
||||
// NOTE: ShorthandStyleValue should be the only valid option here. We implicitly VERIFY this below.
|
||||
if (!font_style_value_result || !font_style_value_result->is_shorthand()) {
|
||||
return;
|
||||
}
|
||||
my_drawing_state().font_style_value = font_style_value_result.release_nonnull();
|
||||
|
||||
// Load font with font style value properties
|
||||
auto const& font_style_value = my_drawing_state().font_style_value->as_shorthand();
|
||||
auto& canvas_element = reinterpret_cast<IncludingClass&>(*this).canvas_element();
|
||||
|
||||
auto& font_style = *font_style_value.longhand(CSS::PropertyID::FontStyle);
|
||||
auto& font_weight = *font_style_value.longhand(CSS::PropertyID::FontWeight);
|
||||
auto& font_width = *font_style_value.longhand(CSS::PropertyID::FontWidth);
|
||||
auto& font_size = *font_style_value.longhand(CSS::PropertyID::FontSize);
|
||||
auto& font_family = *font_style_value.longhand(CSS::PropertyID::FontFamily);
|
||||
|
||||
// https://drafts.csswg.org/css-font-loading/#font-source
|
||||
auto font_source = get_font_source_for_font_style_source_object(canvas_element);
|
||||
|
||||
auto font_list = font_source.visit(
|
||||
[&](DOM::Document* document) -> RefPtr<Gfx::FontCascadeList const> {
|
||||
auto computed_math_depth = CSS::InitialValues::math_depth();
|
||||
auto inherited_math_depth = CSS::InitialValues::math_depth();
|
||||
|
||||
// NOTE: The initial value here is non-standard as the default font is "10px sans-serif"
|
||||
auto inherited_font_size = CSSPixels { 10 };
|
||||
auto inherited_font_weight = CSS::InitialValues::font_weight();
|
||||
// FIXME: Investigate whether this is the correct resolution context (i.e. whether we should instead use
|
||||
// a font-size of 10px) for OffscreenCanvas
|
||||
auto length_resolution_context = CSS::Length::ResolutionContext::for_window(*document->window());
|
||||
Optional<DOM::AbstractElement> abstract_element;
|
||||
|
||||
if constexpr (SameAs<CanvasType, HTML::HTMLCanvasElement>) {
|
||||
// NOTE: The canvas itself is considered the inheritance parent
|
||||
if (canvas_element.computed_properties()) {
|
||||
// NOTE: Since we can't set a math depth directly here we always use the inherited value for the computed value
|
||||
computed_math_depth = canvas_element.computed_properties()->math_depth();
|
||||
inherited_math_depth = canvas_element.computed_properties()->math_depth();
|
||||
inherited_font_size = canvas_element.computed_properties()->font_size();
|
||||
inherited_font_weight = canvas_element.computed_properties()->font_weight();
|
||||
|
||||
abstract_element = DOM::AbstractElement { canvas_element };
|
||||
|
||||
length_resolution_context = CSS::Length::ResolutionContext::for_element(abstract_element.value());
|
||||
}
|
||||
}
|
||||
|
||||
CSS::ComputationContext computation_context {
|
||||
.length_resolution_context = length_resolution_context,
|
||||
.abstract_element = abstract_element
|
||||
};
|
||||
|
||||
// FIXME: Should font be recomputed on canvas element style change?
|
||||
auto const& computed_font_size = CSS::StyleComputer::compute_font_size(font_size, computed_math_depth, inherited_font_size, inherited_math_depth, computation_context);
|
||||
auto const& computed_font_weight = CSS::StyleComputer::compute_font_weight(font_weight, inherited_font_weight, computation_context);
|
||||
auto const& computed_font_width = CSS::StyleComputer::compute_font_width(font_width, computation_context);
|
||||
auto const& computed_font_style = CSS::StyleComputer::compute_font_style(font_style, computation_context);
|
||||
|
||||
return document->style_computer().compute_font_for_style_values(
|
||||
font_family,
|
||||
computed_font_size->as_length().length().absolute_length_to_px(),
|
||||
computed_font_style->as_font_style().to_font_slope(),
|
||||
computed_font_weight->as_number().number(),
|
||||
computed_font_width->as_percentage().percentage());
|
||||
},
|
||||
[](HTML::WorkerGlobalScope*) -> RefPtr<Gfx::FontCascadeList const> {
|
||||
// FIXME: implement computing the font for HTML::WorkerGlobalScope
|
||||
return {};
|
||||
});
|
||||
|
||||
if (!font_list)
|
||||
return;
|
||||
|
||||
my_drawing_state().current_font_cascade_list = font_list;
|
||||
}
|
||||
Variant<DOM::Document*, HTML::WorkerGlobalScope*> get_font_source_for_font_style_source_object(CanvasType& font_style_source_object);
|
||||
|
||||
Bindings::CanvasTextAlign text_align() const { return my_drawing_state().text_align; }
|
||||
void set_text_align(Bindings::CanvasTextAlign text_align) { my_drawing_state().text_align = text_align; }
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <LibWeb/HTML/OffscreenCanvasRenderingContext2D.h>
|
||||
#include <LibWeb/HTML/Scripting/TemporaryExecutionContext.h>
|
||||
#include <LibWeb/HTML/Window.h>
|
||||
#include <LibWeb/HTML/WorkerGlobalScope.h>
|
||||
#include <LibWeb/Platform/EventLoopPlugin.h>
|
||||
#include <LibWeb/WebGL/WebGL2RenderingContext.h>
|
||||
#include <LibWeb/WebGL/WebGLRenderingContext.h>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2025, Lucien Fiorini <lucienfiorini@gmail.com>
|
||||
* Copyright (c) 2025, Callum Law <callumlaw1709@outlook.com>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "SVGFilterPrimitiveStandardAttributes.h"
|
||||
#include <LibWeb/SVG/SVGFEBlendElement.h>
|
||||
#include <LibWeb/SVG/SVGFEColorMatrixElement.h>
|
||||
#include <LibWeb/SVG/SVGFECompositeElement.h>
|
||||
#include <LibWeb/SVG/SVGFEFloodElement.h>
|
||||
#include <LibWeb/SVG/SVGFEGaussianBlurElement.h>
|
||||
#include <LibWeb/SVG/SVGFEImageElement.h>
|
||||
#include <LibWeb/SVG/SVGFEMergeElement.h>
|
||||
#include <LibWeb/SVG/SVGFEOffsetElement.h>
|
||||
|
||||
namespace Web::SVG {
|
||||
|
||||
template<typename IncludingClass>
|
||||
GC::Ref<SVGAnimatedLength> SVGFilterPrimitiveStandardAttributes<IncludingClass>::x()
|
||||
{
|
||||
return this_svg_element()->svg_animated_length_for_property(CSS::PropertyID::X);
|
||||
}
|
||||
|
||||
template<typename IncludingClass>
|
||||
GC::Ref<SVGAnimatedLength> SVGFilterPrimitiveStandardAttributes<IncludingClass>::y()
|
||||
{
|
||||
return this_svg_element()->svg_animated_length_for_property(CSS::PropertyID::Y);
|
||||
}
|
||||
|
||||
template<typename IncludingClass>
|
||||
GC::Ref<SVGAnimatedLength> SVGFilterPrimitiveStandardAttributes<IncludingClass>::width()
|
||||
{
|
||||
return this_svg_element()->svg_animated_length_for_property(CSS::PropertyID::Width);
|
||||
}
|
||||
|
||||
template<typename IncludingClass>
|
||||
GC::Ref<SVGAnimatedLength> SVGFilterPrimitiveStandardAttributes<IncludingClass>::height()
|
||||
{
|
||||
return this_svg_element()->svg_animated_length_for_property(CSS::PropertyID::Height);
|
||||
}
|
||||
|
||||
template<typename IncludingClass>
|
||||
GC::Ref<SVGAnimatedString> SVGFilterPrimitiveStandardAttributes<IncludingClass>::result()
|
||||
{
|
||||
if (!m_result_animated_string)
|
||||
m_result_animated_string = SVGAnimatedString::create(this_svg_element()->realm(), *this_svg_element(), AttributeNames::result);
|
||||
|
||||
return *m_result_animated_string;
|
||||
}
|
||||
|
||||
template class SVGFilterPrimitiveStandardAttributes<SVGFEBlendElement>;
|
||||
template class SVGFilterPrimitiveStandardAttributes<SVGFEColorMatrixElement>;
|
||||
template class SVGFilterPrimitiveStandardAttributes<SVGFECompositeElement>;
|
||||
template class SVGFilterPrimitiveStandardAttributes<SVGFEFloodElement>;
|
||||
template class SVGFilterPrimitiveStandardAttributes<SVGFEGaussianBlurElement>;
|
||||
template class SVGFilterPrimitiveStandardAttributes<SVGFEImageElement>;
|
||||
template class SVGFilterPrimitiveStandardAttributes<SVGFEMergeElement>;
|
||||
template class SVGFilterPrimitiveStandardAttributes<SVGFEOffsetElement>;
|
||||
|
||||
}
|
||||
|
|
@ -16,33 +16,11 @@ class SVGFilterPrimitiveStandardAttributes {
|
|||
public:
|
||||
virtual ~SVGFilterPrimitiveStandardAttributes() = default;
|
||||
|
||||
GC::Ref<SVGAnimatedLength> x()
|
||||
{
|
||||
return this_svg_element()->svg_animated_length_for_property(CSS::PropertyID::X);
|
||||
}
|
||||
|
||||
GC::Ref<SVGAnimatedLength> y()
|
||||
{
|
||||
return this_svg_element()->svg_animated_length_for_property(CSS::PropertyID::Y);
|
||||
}
|
||||
|
||||
GC::Ref<SVGAnimatedLength> width()
|
||||
{
|
||||
return this_svg_element()->svg_animated_length_for_property(CSS::PropertyID::Width);
|
||||
}
|
||||
|
||||
GC::Ref<SVGAnimatedLength> height()
|
||||
{
|
||||
return this_svg_element()->svg_animated_length_for_property(CSS::PropertyID::Height);
|
||||
}
|
||||
|
||||
GC::Ref<SVGAnimatedString> result()
|
||||
{
|
||||
if (!m_result_animated_string)
|
||||
m_result_animated_string = SVGAnimatedString::create(this_svg_element()->realm(), *this_svg_element(), AttributeNames::result);
|
||||
|
||||
return *m_result_animated_string;
|
||||
}
|
||||
GC::Ref<SVGAnimatedLength> x();
|
||||
GC::Ref<SVGAnimatedLength> y();
|
||||
GC::Ref<SVGAnimatedLength> width();
|
||||
GC::Ref<SVGAnimatedLength> height();
|
||||
GC::Ref<SVGAnimatedString> result();
|
||||
|
||||
protected:
|
||||
void visit_edges(JS::Cell::Visitor& visitor)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue