srctree

Robin Linden parent ee14591e 307044b6
style: Make font-weight less stringly typed

inlinesplit
style/styled_node.cpp added: 121, removed: 5, total 116
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2021-2023 Robin Lindén <dev@robinlinden.eu>
// SPDX-FileCopyrightText: 2021-2024 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
@@ -535,6 +535,80 @@ int StyledNode::get_font_size_property() const {
return 0;
}
 
// https://drafts.csswg.org/css-fonts-4/#font-weight-prop
std::optional<FontWeight> StyledNode::get_font_weight_property() const {
auto raw = get_raw_property(css::PropertyId::FontWeight);
if (raw == "normal") {
return FontWeight::normal();
}
 
if (raw == "bold") {
return FontWeight::bold();
}
 
if (raw == "bolder") {
auto parent_weight = [&] {
if (parent == nullptr) {
return FontWeight::normal();
}
 
return parent->get_font_weight_property().value_or(FontWeight::normal());
}();
 
// https://drafts.csswg.org/css-fonts-4/#relative-weights
if (parent_weight.value < 350) {
return FontWeight::normal();
}
 
if (parent_weight.value < 550) {
return FontWeight::bold();
}
 
if (parent_weight.value < 900) {
return FontWeight{900};
}
 
return parent_weight;
}
 
if (raw == "lighter") {
auto parent_weight = [&] {
if (parent == nullptr) {
return FontWeight::normal();
}
 
return parent->get_font_weight_property().value_or(FontWeight::normal());
}();
 
// https://drafts.csswg.org/css-fonts-4/#relative-weights
if (parent_weight.value < 100) {
return parent_weight;
}
 
if (parent_weight.value < 550) {
return FontWeight{100};
}
 
if (parent_weight.value < 750) {
return FontWeight::normal();
}
 
return FontWeight::bold();
}
 
int weight{-1};
if (auto res = std::from_chars(raw.data(), raw.data() + raw.size(), weight);
res.ec != std::errc{} || res.ptr != raw.data() + raw.size()) {
return std::nullopt;
}
 
if (weight < 1 || weight > 1000) {
return std::nullopt;
}
 
return FontWeight{weight};
}
 
std::optional<WhiteSpace> StyledNode::get_white_space_property() const {
auto raw = get_raw_property(css::PropertyId::WhiteSpace);
if (raw == "normal") {
 
style/styled_node.h added: 121, removed: 5, total 116
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2021-2023 Robin Lindén <dev@robinlinden.eu>
// SPDX-FileCopyrightText: 2021-2024 Robin Lindén <dev@robinlinden.eu>
//
// SPDX-License-Identifier: BSD-2-Clause
 
@@ -47,6 +47,15 @@ enum class FontStyle {
Oblique,
};
 
struct FontWeight {
int value{};
[[nodiscard]] constexpr bool operator==(FontWeight const &) const = default;
static constexpr int kNormal = 400;
static constexpr int kBold = 700;
static constexpr FontWeight normal() { return {kNormal}; }
static constexpr FontWeight bold() { return {kBold}; }
};
 
enum class TextDecorationLine {
None,
Underline,
@@ -106,6 +115,8 @@ struct StyledNode {
return get_font_size_property();
} else if constexpr (T == css::PropertyId::FontStyle) {
return get_font_style_property();
} else if constexpr (T == css::PropertyId::FontWeight) {
return get_font_weight_property();
} else if constexpr (T == css::PropertyId::TextDecorationLine) {
return get_text_decoration_line_property();
} else if constexpr (T == css::PropertyId::WhiteSpace) {
@@ -122,6 +133,7 @@ private:
DisplayValue get_display_property() const;
FontStyle get_font_style_property() const;
int get_font_size_property() const;
std::optional<FontWeight> get_font_weight_property() const;
std::vector<TextDecorationLine> get_text_decoration_line_property() const;
std::optional<WhiteSpace> get_white_space_property() const;
};
 
style/styled_node_test.cpp added: 121, removed: 5, total 116
@@ -392,5 +392,35 @@ int main() {
std::vector{style::TextDecorationLine::Blink});
});
 
etest::test("get_property, font-weight", [] {
expect_property_eq<css::PropertyId::FontWeight>("normal", style::FontWeight::normal());
expect_property_eq<css::PropertyId::FontWeight>("bold", style::FontWeight::bold());
 
expect_property_eq<css::PropertyId::FontWeight>("123", style::FontWeight{123});
 
expect_relative_property_eq<css::PropertyId::FontWeight>("bolder", "50", style::FontWeight::normal());
expect_relative_property_eq<css::PropertyId::FontWeight>("bolder", "normal", style::FontWeight::bold());
expect_relative_property_eq<css::PropertyId::FontWeight>("bolder", "bold", style::FontWeight{900});
expect_relative_property_eq<css::PropertyId::FontWeight>("bolder", "999", style::FontWeight{999});
 
expect_relative_property_eq<css::PropertyId::FontWeight>("lighter", "50", style::FontWeight{50});
expect_relative_property_eq<css::PropertyId::FontWeight>("lighter", "normal", style::FontWeight{100});
expect_relative_property_eq<css::PropertyId::FontWeight>("lighter", "bold", style::FontWeight::normal());
expect_relative_property_eq<css::PropertyId::FontWeight>("lighter", "999", style::FontWeight::bold());
 
// Invalid values.
expect_property_eq<css::PropertyId::FontWeight>("???", std::nullopt);
expect_property_eq<css::PropertyId::FontWeight>("0", std::nullopt);
expect_property_eq<css::PropertyId::FontWeight>("1001", std::nullopt);
expect_property_eq<css::PropertyId::FontWeight>("500px", std::nullopt);
 
// Relative, no parent
dom::Node dom = dom::Element{"baka"};
style::StyledNode styled_node{.node = dom, .properties = {{css::PropertyId::FontWeight, "bolder"s}}};
expect_eq(styled_node.get_property<css::PropertyId::FontWeight>(), style::FontWeight::bold());
styled_node.properties[0] = {css::PropertyId::FontWeight, "lighter"s};
expect_eq(styled_node.get_property<css::PropertyId::FontWeight>(), style::FontWeight{100});
});
 
return etest::run_all_tests();
}