Skip to content

Commit 824c327

Browse files
committed
Resolve relative pseudo font sizes
1 parent dd39f11 commit 824c327

8 files changed

Lines changed: 96 additions & 24 deletions

‎experiments/WebScene.NativeEngine.Probe/CMakeLists.txt‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,15 @@ else()
622622
endif()
623623

624624
if(BUILD_TESTING)
625+
add_executable(webscene_css_pseudo_font_size_tests
626+
tests/css_pseudo_font_size_tests.cpp
627+
native/webscene_native_dom.cpp)
628+
target_compile_features(webscene_css_pseudo_font_size_tests PRIVATE cxx_std_20)
629+
target_include_directories(webscene_css_pseudo_font_size_tests PRIVATE native)
630+
add_test(NAME webscene_css_pseudo_font_size_tests
631+
COMMAND webscene_css_pseudo_font_size_tests)
632+
set_tests_properties(webscene_css_pseudo_font_size_tests PROPERTIES
633+
LABELS "native;css;layout;performance" TIMEOUT 10)
625634
add_executable(webscene_css_property_identity_tests
626635
tests/css_property_identity_tests.cpp
627636
native/webscene_native_dom.cpp)

‎experiments/WebScene.NativeEngine.Probe/native/webscene_css_pseudo_application.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22
#include "webscene_css_pseudo_values.h"
3+
#include "webscene_css_text_values.h"
34
#include "webscene_css_variables.h"
45

56
namespace webscene_native::css {
@@ -125,6 +126,9 @@ void apply_pseudo_declaration(dom_node& node,node_style::pseudo_element& pseudo,
125126
}
126127
const auto result = css::apply_pseudo_value(
127128
pseudo, node.style.foreground_rgba, node.style.border_box, name, value);
129+
if (name == "font-size" && result.classification == "supported") {
130+
pseudo.font_size = resolved_pseudo_font_size(node, value);
131+
}
128132
if (name == "font-family" && result.classification == "supported") {
129133
pseudo.font_family_important = declaration.important;
130134
}

‎experiments/WebScene.NativeEngine.Probe/native/webscene_css_text_values.h‎

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,25 +56,43 @@ inline float resolved_word_spacing(const dom_node& node)
5656
return 0;
5757
}
5858

59-
inline float resolved_declared_font_size(const dom_node& node, const std::string& value)
59+
inline float resolved_declared_font_size_from_parent(
60+
const dom_node& node,
61+
const std::string& value,
62+
float parent_font_size)
6063
{
6164
if (value == "inherit" || value == "unset") return -1.0F;
6265
if (value == "initial" || value == "revert") return 14.0F;
6366
const auto parsed = native_document::parse_length(value);
6467
if (parsed.unit == length_unit::em) {
65-
return std::max(0.0F, parsed.value * inherited_font_size(node));
68+
return std::max(0.0F, parsed.value * parent_font_size);
6669
}
6770
if (parsed.unit == length_unit::rem) {
6871
const auto root_size = node.tag == "html" ? 16.0F : document_root_font_size(node);
6972
return std::max(0.0F, parsed.value * root_size);
7073
}
7174
if (parsed.unit == length_unit::percent) {
7275
return std::max(0.0F,
73-
parsed.value * inherited_font_size(node) / 100.0F + parsed.pixel_offset);
76+
parsed.value * parent_font_size / 100.0F + parsed.pixel_offset);
7477
}
7578
return std::max(0.0F, parsed.value);
7679
}
7780

81+
inline float resolved_declared_font_size(const dom_node& node, const std::string& value)
82+
{
83+
return resolved_declared_font_size_from_parent(
84+
node, value, inherited_font_size(node));
85+
}
86+
87+
inline float resolved_pseudo_font_size(const dom_node& originating, const std::string& value)
88+
{
89+
const auto originating_font_size = originating.style.font_size >= 0
90+
? originating.style.font_size
91+
: originating.tag == "html" ? 16.0F : inherited_font_size(originating);
92+
return resolved_declared_font_size_from_parent(
93+
originating, value, originating_font_size);
94+
}
95+
7896
inline float resolved_declared_line_height(
7997
const dom_node& node,
8098
const std::string& value,
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#include "webscene_css_text_values.h"
2+
3+
#include <cmath>
4+
#include <cstdlib>
5+
#include <iostream>
6+
#include <string_view>
7+
8+
namespace {
9+
void require(bool condition, std::string_view message)
10+
{
11+
if (condition) return;
12+
std::cerr << "CSS pseudo font-size test failed: " << message << '\n';
13+
std::exit(1);
14+
}
15+
}
16+
17+
int main()
18+
{
19+
webscene_native::dom_node originating;
20+
originating.tag = "span";
21+
originating.style.font_size = 13.0F;
22+
const auto resolved = [&](const std::string& value) {
23+
return webscene_native::css::resolved_pseudo_font_size(originating, value);
24+
};
25+
require(std::abs(resolved("150%") - 19.5F) < 0.001F,
26+
"150% did not resolve from the originating 13px size");
27+
require(std::abs(resolved("1.5em") - 19.5F) < 0.001F,
28+
"1.5em did not resolve from the originating 13px size");
29+
require(std::abs(resolved("19.5px") - 19.5F) < 0.001F,
30+
"absolute pixels changed during pseudo resolution");
31+
require(resolved("inherit") == -1.0F && resolved("unset") == -1.0F,
32+
"inherit and unset did not preserve pseudo inheritance");
33+
require(resolved("initial") == 14.0F,
34+
"initial did not select the engine's medium font size");
35+
std::cout << "CSS pseudo font-size tests passed\n";
36+
}

‎experiments/WebScene.NativeEngine.Probe/tests/native_v8_runtime_rendering_metrics_tests.inc‎

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -816,10 +816,10 @@ void test_generated_pseudo_font_family_scene_and_scale_gate()
816816
auto advance = font_size * 3.0F;
817817
if (selected.find("FixtureIconAlternate") != std::string_view::npos) {
818818
++state.alternate_calls;
819-
advance = 18.0F;
819+
advance = font_size * 0.9F;
820820
} else if (selected.find("FixtureIcon") != std::string_view::npos) {
821821
++state.fixture_calls;
822-
advance = 12.0F;
822+
advance = font_size * 0.6F;
823823
} else if (selected.find("ParentFace") != std::string_view::npos) {
824824
++state.parent_calls;
825825
}
@@ -885,6 +885,9 @@ void test_generated_pseudo_font_family_scene_and_scale_gate()
885885
+ std::string(resource);
886886
}
887887
if (command.rgba != 0x0C2238FFU) continue;
888+
require(resource.starts_with("19.5\t"),
889+
"generated pseudo text command did not serialize the resolved 19.5px size: "
890+
+ std::string(resource));
888891
const auto family_field = "\t" + std::string(expected_family) + "\t";
889892
require(resource.find(family_field) != std::string_view::npos,
890893
"generated pseudo text command used the originating font family: "
@@ -927,10 +930,10 @@ void test_generated_pseudo_font_family_scene_and_scale_gate()
927930
const rules = document.createElement('style');
928931
rules.id = 'pseudo-font-rules';
929932
rules.textContent = `
930-
.icon-host { display:block; font-family:ParentFace; height:20px; }
933+
.icon-host { display:block; font-family:ParentFace; font-size:13px; height:20px; }
931934
.icon-host::before { content:'\\e023'; display:inline-block;
932935
color:rgb(12,34,56); font-family:FixtureIcon;
933-
font-size:20px; line-height:20px; }
936+
font-size:150%; line-height:20px; }
934937
#single-icon::before { font-family:WrongFace; }
935938
.icon-host::before { font-family:FixtureIcon !important; }
936939
.icon-host.alternate::before { font-family:FixtureIconAlternate !important; }
@@ -943,27 +946,27 @@ void test_generated_pseudo_font_family_scene_and_scale_gate()
943946
document.body.appendChild(host);
944947
})()
945948
)JS", "native-pseudo-font-family-setup.js");
946-
const auto initial = capture("FixtureIcon", 12.0F, 1U);
949+
const auto initial = capture("FixtureIcon", 11.7F, 1U);
947950
execute(engine,
948951
"document.getElementById('single-icon').classList.add('inherited')",
949952
"native-pseudo-font-family-inherit.js");
950-
const auto inherited = capture("ParentFace", 60.0F, 1U);
953+
const auto inherited = capture("ParentFace", 58.5F, 1U);
951954
execute(engine,
952955
"document.getElementById('single-icon').classList.remove('inherited')",
953956
"native-pseudo-font-family-inherit-restore.js");
954-
const auto inherited_restored = capture("FixtureIcon", 12.0F, 1U);
957+
const auto inherited_restored = capture("FixtureIcon", 11.7F, 1U);
955958
require(initial.checksum != inherited.checksum
956959
&& initial.checksum == inherited_restored.checksum
957960
&& initial.node_ids == inherited_restored.node_ids,
958961
"pseudo font-family inheritance did not exactly restore retained scene identity");
959962
execute(engine,
960963
"document.getElementById('single-icon').classList.add('alternate')",
961964
"native-pseudo-font-family-alternate.js");
962-
const auto alternate = capture("FixtureIconAlternate", 18.0F, 1U);
965+
const auto alternate = capture("FixtureIconAlternate", 17.55F, 1U);
963966
execute(engine,
964967
"document.getElementById('single-icon').classList.remove('alternate')",
965968
"native-pseudo-font-family-restore.js");
966-
const auto restored = capture("FixtureIcon", 12.0F, 1U);
969+
const auto restored = capture("FixtureIcon", 11.7F, 1U);
967970
require(initial.checksum != alternate.checksum
968971
&& initial.checksum == restored.checksum
969972
&& initial.node_ids == restored.node_ids,
@@ -980,10 +983,11 @@ void test_generated_pseudo_font_family_scene_and_scale_gate()
980983
(() => {
981984
const rules = document.getElementById('pseudo-font-rules');
982985
rules.textContent += `
983-
#bulk > .bulk-icon { display:block; height:20px; font-family:ParentFace; }
986+
#bulk > .bulk-icon { display:block; height:20px; font-family:ParentFace;
987+
font-size:13px; }
984988
#bulk > .bulk-icon::before { content:'\\e023'; display:inline-block;
985989
color:rgb(12,34,56); font-family:FixtureIcon;
986-
font-size:20px; line-height:20px; }
990+
font-size:150%; line-height:20px; }
987991
#bulk.alternate > .bulk-icon::before { font-family:FixtureIconAlternate; }
988992
`;
989993
const bulk = document.createElement('main');
@@ -1001,13 +1005,13 @@ void test_generated_pseudo_font_family_scene_and_scale_gate()
10011005
require(evaluate(engine, "document.getElementById('bulk').children.length",
10021006
"native-pseudo-font-family-scale-count.js") == "4096",
10031007
"pseudo font-family scale fixture did not create 4,096 icons");
1004-
const auto bulk_initial = capture("FixtureIcon", 12.0F, 4096U);
1008+
const auto bulk_initial = capture("FixtureIcon", 11.7F, 4096U);
10051009
execute(engine, "document.getElementById('bulk').classList.add('alternate')",
10061010
"native-pseudo-font-family-scale-alternate.js");
1007-
const auto bulk_alternate = capture("FixtureIconAlternate", 18.0F, 4096U);
1011+
const auto bulk_alternate = capture("FixtureIconAlternate", 17.55F, 4096U);
10081012
execute(engine, "document.getElementById('bulk').classList.remove('alternate')",
10091013
"native-pseudo-font-family-scale-restore.js");
1010-
const auto bulk_restored = capture("FixtureIcon", 12.0F, 4096U);
1014+
const auto bulk_restored = capture("FixtureIcon", 11.7F, 4096U);
10111015
require(bulk_initial.checksum != bulk_alternate.checksum
10121016
&& bulk_initial.checksum == bulk_restored.checksum
10131017
&& bulk_initial.node_ids == bulk_restored.node_ids,
@@ -1036,7 +1040,7 @@ void test_generated_pseudo_font_family_scene_and_scale_gate()
10361040
require(elapsed < 5000.0,
10371041
"4,096 pseudo icons across 100 family cycles exceeded 5 seconds: "
10381042
+ std::to_string(elapsed));
1039-
const auto bulk_after_cycles = capture("FixtureIcon", 12.0F, 4096U);
1043+
const auto bulk_after_cycles = capture("FixtureIcon", 11.7F, 4096U);
10401044
require(bulk_after_cycles.checksum == bulk_initial.checksum
10411045
&& bulk_after_cycles.node_ids == bulk_initial.node_ids,
10421046
"scaled family cycles did not restore the original retained scene");

‎tests/WebPlatformSubset/contracts/css-pseudo-icon-font-family-ref.html‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<!doctype html>
22
<meta charset="utf-8">
3-
<title>Reference for generated pseudo downloadable icon font</title>
3+
<title>Reference for generated pseudo downloadable icon font and relative size</title>
44
<style>
55
/* Subset of tests/Fonts/Roboto/Roboto-400.ttf (OFL.txt): U+E023 maps to H; U+E099 maps to X. */
66
@font-face { font-family: FixtureIcon; src: url("data:font/woff2;base64,AAEAAAAPAIAAAwBwR0RFRgARAAIAAALUAAAAFkdQT1NEdkx1AAAC7AAAACBHU1VCkxWCFgAAAwwAAAA2T1MvMlKNUiIAAAF4AAAAYFNUQVRfnUM1AAADRAAAAF5jbWFw4SHgCgAAAeQAAAA8Z2FzcAAIABkAAALIAAAADGdseWYwT/DgAAACKAAAAHhoZWFkEDQiOQAAAPwAAAA2aGhlYQywC/oAAAE0AAAAJGhtdHgORQFHAAAB2AAAAAxsb2NhABsAPAAAAiAAAAAIbWF4cAAHAA0AAAFYAAAAIG5hbWUABgAAAAACoAAAAAZwb3N0/20AZAAAAqgAAAAgAAEAAAADA9eI9yBeXw889QAbCAAAAAAAxPARLgAAAADm0cKGADoAAAUIBbAAAAAJAAIAAAAAAAAAAQAAB2z+DAAABbUAOgA2BQgIAAAAAAAAAAAAAAAAAAAAAAMAAQAAAAMADAADAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAEBIQBkAAFAAAFmgUzAAABHwWaBTMAAAPRAGYCAAAAAgAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAABHT09HAEDgI+CZBgD+AABmB5oCAAAAAAEAAAAABDoFsAAAACAAAwOMAGQFtQCpBQQAOgAAAAIAAAADAAAAFAADAAEAAAAUAAQAKAAAAAYABAABAALgI+CZ//8AAOAj4Jn//x/eH2kAAQAAAAAAAAAAAAAAGwA8AAMAqQAABQgFsAADAAcACwAAQRUhNRMRIxEhESMRBGD87B7BBF/AAz6dnQJy+lAFsPpQBbAAAAEAOgAABM4FsAALAABBAQEzAQEjAQEjAQEBJgFeAV7h/jQB1+P+mf6Z4wHX/jQFsP3SAi79L/0hAjn9xwLfAtEAAAAAAAAGAAAAAwAAAAAAAP9qAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAIACAAI//8ADwABAAAADAAAAAAAAAABAAEAAgABAAEAAAABAAAACgAcAB4AAURGTFQACAAEAAAAAP//AAAAAAAAAAEAAAAKADIANAAEREZMVAAaY3lybAAkZ3JlawAkbGF0bgAkAAQAAAAA//8AAAAAAAAAAAAAAAAAAQABAAgAAwAAABQAAwAAACwAAndkdGgBJQAAd2dodAEoAAFpdGFsATIAAgAGABIAIgABAAAAAgEnAGQAAAADAAEAAgEsAZAAAAK8AAAAAwACAAIBKAAAAAAAAQAAAAA=") format("woff2"); }
@@ -10,7 +10,7 @@
1010
.tab { height: 30px; margin-top: 8px; }
1111
.row { height: 22px; margin-top: 10px; overflow: hidden; }
1212
.icon, .tab::before, .row::before { position: absolute; left: 8px; top: 4px; width: 20px; height: 20px;
13-
font-family: FixtureIcon; font-size: 20px; line-height: 20px; font-weight: 400;
13+
font-family: FixtureIcon; font-size: 150%; line-height: 20px; font-weight: 400;
1414
text-align: left; color: rgb(212, 215, 214); }
1515
.row .icon, .row::before { top: 1px; color: rgb(81, 154, 186); }
1616
.label { position: absolute; left: 34px; top: 8px; }

‎tests/WebPlatformSubset/contracts/css-pseudo-icon-font-family.html‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<!doctype html>
22
<meta charset="utf-8">
3-
<title>Generated pseudo content selects its own downloadable icon font</title>
3+
<title>Generated pseudo content selects its own icon font and relative size</title>
44
<link rel="match" href="css-pseudo-icon-font-family-ref.html">
55
<style>
66
/* Subset of tests/Fonts/Roboto/Roboto-400.ttf (OFL.txt): U+E023 maps to H; U+E099 maps to X. */
@@ -11,7 +11,7 @@
1111
.tab { height: 30px; margin-top: 8px; }
1212
.row { height: 22px; margin-top: 10px; overflow: hidden; }
1313
.icon, .tab::before, .row::before { position: absolute; left: 8px; top: 4px; width: 20px; height: 20px;
14-
font-family: FixtureIcon; font-size: 20px; line-height: 20px; font-weight: 400;
14+
font-family: FixtureIcon; font-size: 150%; line-height: 20px; font-weight: 400;
1515
text-align: left; color: rgb(212, 215, 214); }
1616
.row .icon, .row::before { top: 1px; color: rgb(81, 154, 186); }
1717
.label { position: absolute; left: 34px; top: 8px; }

‎tests/WebPlatformSubset/webscene-pseudo-icon-font-profile.json‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"profile": "webscene-pseudo-icon-font-1",
2+
"profile": "webscene-pseudo-icon-font-2",
33
"wptRevision": "2c705104a295c48053eeddf7fe0170d790a4e853",
44
"runtime": "v8",
55
"viewport": {
@@ -14,11 +14,12 @@
1414
"reference": "contracts/css-pseudo-icon-font-family-ref.html",
1515
"capabilities": [
1616
"generated-pseudo-font-family",
17+
"generated-pseudo-relative-font-size",
1718
"downloadable-font-face",
1819
"private-use-glyph-paint"
1920
],
2021
"evidence": ["code-oss-seti-tab-and-list-icon-reduction"],
21-
"reason": "Exact-pixel reduction of generated icon labels whose originating element uses the system UI face while ::before selects a downloadable icon face. The fixture maps the two private-use code points observed in unchanged Code OSS and compares them with ordinary reference glyph boxes."
22+
"reason": "Exact-pixel reduction of generated icon labels whose originating element uses a 13px system UI face while ::before selects a downloadable icon face at 150%, matching unchanged Code OSS. The fixture maps the two observed private-use code points and compares the computed 19.5px pseudo glyphs with ordinary reference glyph boxes."
2223
}
2324
],
2425
"harnessBlocked": [],

0 commit comments

Comments
 (0)