Skip to content

Commit ba27b13

Browse files
Merge pull request #803 from SceneTech/feature/css-text-wrap-802
Implement CSS text-wrap layout mode
2 parents 0228799 + 82a42d8 commit ba27b13

23 files changed

Lines changed: 237 additions & 8 deletions
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Code OSS CSS text-wrap implementation (#802)
2+
3+
## Product trigger
4+
5+
Unchanged Code OSS has 10 `text-wrap` declarations across 9 CSS files. The
6+
bounded values are `nowrap`, `wrap`, and one `initial` reset across diff and
7+
placeholder text, hovers, Changes, Chat status/anchors/code pills, and notebook
8+
content.
9+
10+
## Implemented slice
11+
12+
- Adds generated native/managed identity, validation, and CSSOM for the
13+
product-used `wrap|nowrap` mode plus CSS-wide reset/inheritance behavior.
14+
- Retains the inherited mode in cold textual style independently from
15+
`white-space`; computed `white-space` therefore remains browser-shaped.
16+
- Composes the mode with the existing retained inline/layout/scene wrap
17+
decision, including word-break and overflow-wrap behavior.
18+
- Uses ordinary coalesced layout invalidation and adds no timer, frame
19+
participant, platform text widget, document scan, browser shell, or Code OSS
20+
patch.
21+
22+
`balance`, `pretty`, `stable`, and the complete Text Level 4 shorthand grammar
23+
remain outside this bounded slice.
24+
25+
## Authored gates
26+
27+
- `contracts/css-text-wrap-mode.html`: inheritance, computed CSSOM, invalid
28+
writes, mutation/removal, overflow, and height change.
29+
- `test_css_text_wrap_layout`: native inheritance and retained geometry.
30+
- `css-text-wrap-performance`: 4,096 text nodes, ten forced layout checkpoints,
31+
bounded layout/publication, and a five-second guardrail.
32+
33+
## Evidence state
34+
35+
Implementation and gates are authored from source review. Per the active fast
36+
merge direction, no build, test, WPT, visual, package, memory, lifecycle, or
37+
performance command was executed. Evidence remains zero until full validation.

‎experiments/WebScene.NativeEngine.Probe/native/css_property_metadata.json‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,8 @@
157157
{"id": "overscroll_behavior_x", "name": "overscroll-behavior-x", "aliases": ["overscrollbehaviorx"]},
158158
{"id": "overscroll_behavior_y", "name": "overscroll-behavior-y", "aliases": ["overscrollbehaviory"]},
159159
{"id": "isolation", "name": "isolation"},
160-
{"id": "will_change", "name": "will-change", "aliases": ["willchange"]}
160+
{"id": "will_change", "name": "will-change", "aliases": ["willchange"]},
161+
{"id": "text_wrap", "name": "text-wrap", "aliases": ["textwrap"]}
161162
],
162163
"nativeStorageOnlyProperties": [
163164
"accent-color", "align-content", "animation-direction", "animation-fill-mode", "animation-play-state",
@@ -179,7 +180,7 @@
179180
"justify_content", "box_sizing", "vertical_align", "grid_auto_flow", "border_collapse", "table_layout", "border_style", "background_repeat",
180181
"visibility", "pointer_events", "text_anchor", "font_smoothing", "text_align", "text_transform", "white_space", "word_break", "overflow_wrap", "list_style_position",
181182
"list_style_type", "scrollbar_width", "container", "container_type", "content_visibility", "object_fit", "user_select",
182-
"overscroll_behavior", "overscroll_behavior_x", "overscroll_behavior_y", "isolation", "will_change"
183+
"overscroll_behavior", "overscroll_behavior_x", "overscroll_behavior_y", "isolation", "will_change", "text_wrap"
183184
],
184185
"componentList": [
185186
"container_name", "background_position", "background_size", "transition", "transition_property", "transition_duration",
@@ -223,7 +224,7 @@
223224
"outline", "outline_width", "outline_color", "animation", "animation_name", "animation_duration", "animation_delay",
224225
"animation_timing_function", "animation_iteration_count", "background_repeat", "background_position", "background_size",
225226
"font", "text_transform", "word_break", "overflow_wrap", "list_style", "list_style_position", "list_style_type",
226-
"object_fit", "object_position", "user_select", "overscroll_behavior", "overscroll_behavior_x", "overscroll_behavior_y", "isolation", "will_change"
227+
"object_fit", "object_position", "user_select", "overscroll_behavior", "overscroll_behavior_x", "overscroll_behavior_y", "isolation", "will_change", "text_wrap"
227228
],
228229
"managedKnownProperties": [
229230
"align-content", "align-items", "align-self", "all", "background", "background-color",
@@ -245,7 +246,7 @@
245246
"top", "transform", "visibility", "white-space", "word-break", "overflow-wrap", "width", "word-spacing", "z-index",
246247
"outline", "outline-color", "outline-offset", "outline-style", "outline-width",
247248
"grid-template-areas", "aspect-ratio", "object-fit", "object-position", "user-select",
248-
"overscroll-behavior", "overscroll-behavior-x", "overscroll-behavior-y", "isolation", "will-change"
249+
"overscroll-behavior", "overscroll-behavior-x", "overscroll-behavior-y", "isolation", "will-change", "text-wrap"
249250
],
250251
"supportedPropertyExtras": [
251252
"animation", "animation-delay", "animation-direction", "animation-duration", "animation-fill-mode",

‎experiments/WebScene.NativeEngine.Probe/native/generated/webscene_css_property_identity.inc‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@ inline constexpr std::array native_typed_property_identity_catalog{
234234
native_typed_property_identity{"isolation", css_property_id::isolation},
235235
native_typed_property_identity{"will-change", css_property_id::will_change},
236236
native_typed_property_identity{"willchange", css_property_id::will_change},
237+
native_typed_property_identity{"text-wrap", css_property_id::text_wrap},
238+
native_typed_property_identity{"textwrap", css_property_id::text_wrap},
237239
};
238240

239241
inline constexpr std::array<std::string_view, 62> native_storage_only_property_catalog{
@@ -459,6 +461,7 @@ inline constexpr std::array native_modeled_property_mask_catalog{
459461
false,
460462
false,
461463
false,
464+
false,
462465
};
463466

464467
inline constexpr bool generated_property_has_modeled_mask(
@@ -663,6 +666,7 @@ inline constexpr std::array native_property_grammar_catalog{
663666
native_property_grammar::keyword,
664667
native_property_grammar::keyword,
665668
native_property_grammar::keyword,
669+
native_property_grammar::keyword,
666670
};
667671

668672
inline constexpr native_property_grammar generated_property_grammar(
@@ -905,5 +909,7 @@ inline css_property_id generated_property_id_lowercase(std::string_view name) no
905909
if (name == "isolation") return css_property_id::isolation;
906910
if (name == "will-change") return css_property_id::will_change;
907911
if (name == "willchange") return css_property_id::will_change;
912+
if (name == "text-wrap") return css_property_id::text_wrap;
913+
if (name == "textwrap") return css_property_id::text_wrap;
908914
return css_property_id::unknown;
909915
}

‎experiments/WebScene.NativeEngine.Probe/native/generated/webscene_css_property_ids.inc‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,4 @@ overscroll_behavior_x,
156156
overscroll_behavior_y,
157157
isolation,
158158
will_change,
159+
text_wrap,

‎experiments/WebScene.NativeEngine.Probe/native/generated/webscene_css_supported_properties.inc‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ inline constexpr std::array cssom_supported_property_catalog{
236236
cssom_supported_property_metadata{"text-indent", "textIndent"},
237237
cssom_supported_property_metadata{"text-overflow", "textOverflow"},
238238
cssom_supported_property_metadata{"text-transform", "textTransform"},
239+
cssom_supported_property_metadata{"text-wrap", "textWrap"},
239240
cssom_supported_property_metadata{"top", "top"},
240241
cssom_supported_property_metadata{"transform", "transform"},
241242
cssom_supported_property_metadata{"transform-origin", "transformOrigin"},
@@ -261,4 +262,4 @@ inline constexpr std::array cssom_supported_property_catalog{
261262
cssom_supported_property_metadata{"zoom", "zoom"},
262263
};
263264

264-
inline constexpr auto cssom_style_template_property_accessor_count = 464U;
265+
inline constexpr auto cssom_style_template_property_accessor_count = 466U;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ inline void reset_cascaded_style(dom_node& node,
226226
}
227227
textual->word_break.clear();
228228
textual->overflow_wrap.clear();
229+
textual->text_wrap.clear();
229230
textual->object_fit.clear();
230231
textual->object_position.clear();
231232
textual->user_select.clear();

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,9 @@ inline void apply_all_unset(
231231
reset.mutable_textual().overflow_wrap =
232232
previous.textual().overflow_wrap;
233233
}
234+
if (has_inline({"text-wrap"})) {
235+
reset.mutable_textual().text_wrap = previous.textual().text_wrap;
236+
}
234237
if (has_inline({"object-fit"})) {
235238
reset.mutable_textual().object_fit =
236239
previous.textual().object_fit;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ inline constexpr auto specified_property_samples = std::to_array<specified_prope
1313
{"overscroll-behavior","contain none"},{"overscroll-behavior-x","auto"},{"overscroll-behavior-y","contain"},
1414
{"isolation","isolate"},
1515
{"will-change","transform, opacity"},
16+
{"text-wrap","nowrap"},
1617
{"width","12px"},{"height","20%"},{"min-width","1rem"},{"min-height","2px"},
1718
{"max-width","none"},{"max-height","fit-content"},
1819
{"left","1px"},{"top","2px"},{"right","3px"},{"bottom","4px"},{"inset","1px 2px 3px 4px"},

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,16 @@ bool apply_text_value(dom_node& node,const std::string& name,const std::string&
406406
node.style.mutable_textual().white_space =
407407
value == "inherit" || value == "unset"
408408
? std::string{} : value;
409+
} else if (name == "text-wrap") {
410+
auto mode = ascii_lower(trim_value(value));
411+
if (mode == "inherit" || mode == "unset") mode.clear();
412+
else if (mode == "initial" || mode == "revert"
413+
|| mode == "revert-layer") mode = "wrap";
414+
if (!mode.empty() && mode != "wrap" && mode != "nowrap") {
415+
decision.classification = "invalid-authoring";
416+
} else {
417+
node.style.mutable_textual().text_wrap = std::move(mode);
418+
}
409419
} else if (name == "word-break") {
410420
node.style.mutable_textual().word_break =
411421
value == "inherit" || value == "unset"

‎experiments/WebScene.NativeEngine.Probe/native/webscene_native_dom.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,7 @@ std::string resolved_text_transform(const dom_node& node, std::string value)
10251025

10261026
bool resolved_white_space_wraps(const dom_node& node)
10271027
{
1028+
if (resolved_text_wrap_mode(node) == "nowrap") return false;
10281029
for (auto* current = &node; current != nullptr; current = current->parent) {
10291030
if (current->style.textual().white_space.empty()) continue;
10301031
return current->style.textual().white_space != "nowrap"

0 commit comments

Comments
 (0)