ladybird/Libraries/LibWeb/SVG/SVGTextPositioningElement.h

82 lines
2.8 KiB
C
Raw Normal View History

/*
* Copyright (c) 2023, MacDue <macdue@dueutil.tech>
* Copyright (c) 2025, Jelle Raaijmakers <jelle@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibWeb/SVG/SVGTextContentElement.h>
namespace Web::SVG {
// https://svgwg.org/svg2-draft/text.html#TSpanNotes
// https://svgwg.org/svg2-draft/text.html#TSpanAttributes
struct TextPositioning {
using Position = Variant<CSS::LengthPercentage, CSS::Number>;
Vector<Position> x;
Vector<Position> y;
Vector<Position> dx;
Vector<Position> dy;
Vector<float> rotate;
void apply_to_text_position(Layout::Node const& node, CSSPixelSize viewport, Gfx::FloatPoint& current_text_position,
size_t character_index) const
{
auto value_for_character = [&](Vector<Position> const& values) -> float {
if (values.is_empty())
return 0.f;
auto position = character_index < values.size() ? values[character_index] : values.last();
return position.visit(
[](CSS::Number const& number) { return static_cast<float>(number.value()); },
[&](CSS::LengthPercentage const& length_percentage) {
auto reference = &values == &x || &values == &dx ? viewport.width() : viewport.height();
return length_percentage.to_px(node, reference).to_float();
});
};
if (!x.is_empty())
current_text_position.set_x(value_for_character(x));
if (!y.is_empty())
current_text_position.set_y(value_for_character(y));
current_text_position.translate_by(value_for_character(dx), value_for_character(dy));
}
};
// https://svgwg.org/svg2-draft/text.html#InterfaceSVGTextPositioningElement
class SVGTextPositioningElement : public SVGTextContentElement {
WEB_PLATFORM_OBJECT(SVGTextPositioningElement, SVGTextContentElement);
public:
virtual void attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_) override;
TextPositioning text_positioning() const;
GC::Ref<SVGAnimatedLengthList> x();
GC::Ref<SVGAnimatedLengthList> y();
GC::Ref<SVGAnimatedLengthList> dx();
GC::Ref<SVGAnimatedLengthList> dy();
GC::Ref<SVGAnimatedNumberList> rotate();
protected:
SVGTextPositioningElement(DOM::Document&, DOM::QualifiedName);
virtual void initialize(JS::Realm&) override;
virtual void visit_edges(Visitor&) override;
private:
GC::Ref<SVGAnimatedLengthList> ensure_length_list(GC::Ptr<SVGAnimatedLengthList>&, FlyString const& attribute_name) const;
GC::Ptr<SVGAnimatedLengthList> m_x;
GC::Ptr<SVGAnimatedLengthList> m_y;
GC::Ptr<SVGAnimatedLengthList> m_dx;
GC::Ptr<SVGAnimatedLengthList> m_dy;
GC::Ptr<SVGAnimatedNumberList> m_rotate;
};
}