Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ jobs:
- run: perl -pi.bak -e 's/opt-level = 2/opt-level = 0/g' Cargo.toml
- run: sudo apt-get update && sudo apt-get install -y libfontconfig1-dev
- run: cargo clippy --workspace -- -D warnings
- run: cargo clippy -p blitz-dom --no-default-features --features svg,woff,accessibility,system-fonts,file-input,custom-widget --all-targets -- -D warnings

ci-scripts:
name: "Test CI scripts"
Expand Down
40 changes: 34 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ taffy = { git = "https://github.com/DioxusLabs/taffy", rev = "16d3443e4c0de68ef1
"calc",
"detailed_layout_info",
] }
parley = { git = "https://github.com/linebender/parley", rev = "e41dfea5cf50669ac67c5a8aca8d1664ffb72904", default-features = false, features = ["std"] }
parley = { git = "https://github.com/linebender/parley", rev = "62790943af982ad3388a3ff96cef6f90ac80a8bb", default-features = false, features = ["std"] }
skrifa = { version = "0.44", default-features = false, features = [
"std",
] } # Should match parley and vello versions
Expand Down Expand Up @@ -192,6 +192,13 @@ rayon = "1"
test-that = "0.5.2"
thread_local = "1"

# Unicode (ICU4X)
icu_casemap = { version = "2.3", default-features = false, features = ["compiled_data"] }
icu_locale_core = { version = "2.3", default-features = false }
icu_properties = { version = "2.3", default-features = false, features = ["compiled_data"] }
icu_segmenter = { version = "2.3", default-features = false, features = ["compiled_data"] }
writeable = { version = "0.6", default-features = false }

[profile.profile]
inherits = "release"
debug = true
Expand Down
2 changes: 1 addition & 1 deletion apps/browser/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ dioxus-native = { workspace = true, features = [
"hot-reload"
] }
blitz-traits = { workspace = true }
blitz-dom = { workspace = true, features = ["woff", "parallel-construct", "floats"] }
blitz-dom = { workspace = true, features = ["woff", "parallel-construct", "floats", "icu-text-transform"] }
blitz-net = { workspace = true, features = ["http2"] }
blitz-html = { workspace = true }
blitz-vibey-script = { workspace = true, optional = true }
Expand Down
13 changes: 12 additions & 1 deletion packages/blitz-dom/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ default = [
"accessibility",
"system-fonts",
"file-input",
"custom-widget"
"custom-widget",
"icu-text-transform"
]
custom-widget = ["dep:anyrender", "accessibility"]
tracing = ["dep:tracing"]
Expand All @@ -28,6 +29,9 @@ accessibility = ["accesskit"]
system-fonts = ["parley/system"]
# complex-scripts: enable dictionary-based line-breaking
complex-scripts = ["parley/complex-scripts"]
# icu-text-transform: language-aware, Unicode-complete case mapping for `text-transform`
# (otherwise falls back to the standard library's case mapping)
icu-text-transform = ["dep:icu_casemap", "dep:writeable"]
autofocus = []
floats = ["taffy/float_layout", "stylo_taffy/floats"]
file-input = []
Expand Down Expand Up @@ -69,6 +73,13 @@ linebender_resource_handle = { workspace = true }
color = { workspace = true }
kurbo = { workspace = true }

# Unicode
icu_casemap = { workspace = true, optional = true }
icu_locale_core = { workspace = true }
icu_properties = { workspace = true }
icu_segmenter = { workspace = true }
writeable = { workspace = true, optional = true }

# Other dependencies
slotmap = { workspace = true }
bitflags = { workspace = true }
Expand Down
82 changes: 56 additions & 26 deletions packages/blitz-dom/src/layout/construct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use style::{
data::ElementData as StyloElementData,
shared_lock::StylesheetGuards,
values::{
computed::{Content, ContentItem, Display, Float, TextTransform},
computed::{Content, ContentItem, Display, Float},
specified::box_::{DisplayInside, DisplayOutside},
},
};
Expand All @@ -36,6 +36,7 @@ use super::{
list::{BULLET_FONT_FAMILY, collect_list_item_children},
replaced::is_inline_box_element,
table::build_table_context,
text_transform::{CaseTransform, TextTransformer},
};

const DUMMY_NAME: QualName = qual_name!("div", html);
Expand Down Expand Up @@ -1066,9 +1067,9 @@ pub(crate) fn build_inline_layout_into(
}

let text_transform = root_node_style
.as_ref()
.map(|s| s.clone_text_transform() & TextTransform::CASE_TRANSFORMS)
.unwrap_or(TextTransform::NONE);
.as_deref()
.map(|s| CaseTransform::from_style(s))
.unwrap_or(CaseTransform::NONE);

// Render position-inside list items
if let Some(ListItemLayout {
Expand All @@ -1093,34 +1094,56 @@ pub(crate) fn build_inline_layout_into(
Marker::String(str) => builder.push_text(str),
}
};
// The marker is a separate box, so words in the content don't continue from it.
let mut text_transformer = TextTransformer::default();
text_transformer.word_break(&builder);

if let Some(before_id) = root_node.before() {
build_inline_layout_recursive(&mut builder, nodes, before_id, text_transform);
build_inline_layout_recursive(
&mut builder,
&mut text_transformer,
nodes,
before_id,
&text_transform,
);
}
for child_id in root_node.children.iter().copied() {
build_inline_layout_recursive(&mut builder, nodes, child_id, text_transform);
build_inline_layout_recursive(
&mut builder,
&mut text_transformer,
nodes,
child_id,
&text_transform,
);
}
if let Some(after_id) = root_node.after() {
build_inline_layout_recursive(&mut builder, nodes, after_id, text_transform);
build_inline_layout_recursive(
&mut builder,
&mut text_transformer,
nodes,
after_id,
&text_transform,
);
}

text_layout.text = builder.build_into(&mut text_layout.layout);
return;

fn build_inline_layout_recursive(
builder: &mut TreeBuilder<TextBrush>,
text_transformer: &mut TextTransformer,
nodes: &crate::NodeTree,
node_id: NodeId,
parent_text_transform: TextTransform,
parent_text_transform: &CaseTransform,
) {
let node = &nodes[node_id];

let style = node.primary_styles();
let style = style.as_ref();

let text_transform = style
.map(|s| s.clone_text_transform() & TextTransform::CASE_TRANSFORMS)
.unwrap_or(TextTransform::NONE);
.map(|s| CaseTransform::from_style(s))
.unwrap_or(CaseTransform::NONE);

match &node.data {
NodeData::Element(element_data) | NodeData::AnonymousBlock(element_data) => {
Expand Down Expand Up @@ -1168,14 +1191,23 @@ pub(crate) fn build_inline_layout_into(
);
for child_id in node.children.iter().copied() {
// node.remove_damage(CONSTRUCT_DESCENDENT | CONSTRUCT_FC | CONSTRUCT_BOX);
build_inline_layout_recursive(builder, nodes, child_id, text_transform);
build_inline_layout_recursive(
builder,
text_transformer,
nodes,
child_id,
&text_transform,
);
}
builder.pop_style_span();
}
(DisplayOutside::Inline, DisplayInside::Flow) => {
let tag_name = &element_data.name.local;

if is_inline_box_element(tag_name) {
if box_kind == InlineBoxKind::InFlow {
text_transformer.word_break(builder);
}
builder.push_inline_box(InlineBox {
id: node_id.as_u64(),
kind: box_kind,
Expand All @@ -1200,6 +1232,7 @@ pub(crate) fn build_inline_layout_into(
]);
builder.push_text("\n");
builder.pop_style_span();
text_transformer.word_break(builder);
} else {
// node.remove_damage(CONSTRUCT_DESCENDENT | CONSTRUCT_FC | CONSTRUCT_BOX);
let style = node
Expand All @@ -1215,26 +1248,29 @@ pub(crate) fn build_inline_layout_into(
if let Some(before_id) = node.before() {
build_inline_layout_recursive(
builder,
text_transformer,
nodes,
before_id,
text_transform,
&text_transform,
);
}

for child_id in node.children.iter().copied() {
build_inline_layout_recursive(
builder,
text_transformer,
nodes,
child_id,
text_transform,
&text_transform,
);
}
if let Some(after_id) = node.after() {
build_inline_layout_recursive(
builder,
text_transformer,
nodes,
after_id,
text_transform,
&text_transform,
);
}

Expand All @@ -1243,6 +1279,9 @@ pub(crate) fn build_inline_layout_into(
}
// Inline box
(_, _) => {
if box_kind == InlineBoxKind::InFlow {
text_transformer.word_break(builder);
}
builder.push_inline_box(InlineBox {
id: node_id.as_u64(),
kind: box_kind,
Expand All @@ -1264,18 +1303,9 @@ pub(crate) fn build_inline_layout_into(
// node.remove_damage(CONSTRUCT_DESCENDENT | CONSTRUCT_FC | CONSTRUCT_BOX);
// dbg!(&data.content);

// TODO: optimize case transforms to be non-allocating
match parent_text_transform {
TextTransform::UPPERCASE => {
builder.push_text(&data.content.to_uppercase());
}
TextTransform::LOWERCASE => {
builder.push_text(&data.content.to_lowercase());
}
_ => {
builder.push_text(&data.content);
}
}
let text =
text_transformer.transform(&data.content, parent_text_transform, builder);
builder.push_text(text);
}
NodeData::Comment { .. } => {
// node.remove_damage(CONSTRUCT_DESCENDENT | CONSTRUCT_FC | CONSTRUCT_BOX);
Expand Down
1 change: 1 addition & 0 deletions packages/blitz-dom/src/layout/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub(crate) mod list;
pub(crate) mod paint_tree;
pub(crate) mod replaced;
pub(crate) mod table;
pub(crate) mod text_transform;

use self::replaced::{
IntrinsicSizes, ReplacedContext, compute_replaced_layout, is_replaced_element,
Expand Down
Loading
Loading