Skip to content
Draft
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
281 changes: 159 additions & 122 deletions Cargo.lock

Large diffs are not rendered by default.

36 changes: 19 additions & 17 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ debug_timer = { version = "0.1.2", path = "./packages/debug_timer" }
accesskit_xplat = { version = "0.1", path = "./packages/accesskit_xplat", default-features = false }

# Servo dependencies
style = { version = "0.12.0", package = "stylo" }
style_traits = { version = "0.12.0", package = "stylo_traits" }
style_atoms = { version = "0.12.0", package = "stylo_atoms" }
style_config = { version = "0.12.0", package = "stylo_config" }
style_dom = { version = "0.12.0", package = "stylo_dom" }
selectors = { version = "0.35.0", package = "selectors" }
style = { version = "0.14.0", package = "stylo" }
style_traits = { version = "0.14.0", package = "stylo_traits" }
style_atoms = { version = "0.14.0", package = "stylo_atoms" }
style_dom = { version = "0.14.0", package = "stylo_dom" }
static_prefs = { version = "0.14.0", package = "stylo_static_prefs" }
selectors = { version = "0.36.0", package = "selectors" }
cssparser = { version = "0.36" }

# HTML5ever dependencies
Expand Down Expand Up @@ -255,18 +255,20 @@ tracing-subscriber = "0.3"
# vello_hybrid = { path = "../vello/sparse_strips/vello_hybrid" }
# vello_common = { path = "../vello/sparse_strips/vello_common" }

# [patch.crates-io]
# style = { path = "../stylo/style", package = "stylo" }
# style_traits = { path = "../stylo/style_traits", package = "stylo_traits" }
# style_atoms = { path = "../stylo/stylo_atoms", package = "stylo_atoms" }
# style_config = { path = "../stylo/stylo_config", package = "stylo_config" }
# style_dom = { path = "../stylo/stylo_dom", package = "stylo_dom" }
# selectors = { path = "../stylo/selectors", package = "selectors" }

# [patch.crates-io]
# [patch."https://github.com/dioxuslabs/taffy"]
# taffy = { path = "../taffy" }

# [patch."https://github.com/linebender/parley"]
# parley = { path = "../parley/parley" }
# fontique = { path = "../parley/fontique" }
[patch."https://github.com/linebender/parley"]
parley = { path = "/Users/jonathankelley/Development/Tinkering/parley/parley" }
fontique = { path = "/Users/jonathankelley/Development/Tinkering/parley/fontique" }

[patch."crates-io"]
parley = { path = "/Users/jonathankelley/Development/Tinkering/parley/parley" }
fontique = { path = "/Users/jonathankelley/Development/Tinkering/parley/fontique" }
style = { path = "/Users/jonathankelley/Development/Tinkering/stylo/style", package = "stylo" }
style_traits = { path = "/Users/jonathankelley/Development/Tinkering/stylo/style_traits", package = "stylo_traits" }
style_atoms = { path = "/Users/jonathankelley/Development/Tinkering/stylo/stylo_atoms", package = "stylo_atoms" }
style_dom = { path = "/Users/jonathankelley/Development/Tinkering/stylo/stylo_dom", package = "stylo_dom" }
static_prefs = { path = "/Users/jonathankelley/Development/Tinkering/stylo/stylo_static_prefs", package = "stylo_static_prefs" }
selectors = { path = "/Users/jonathankelley/Development/Tinkering/stylo/selectors", package = "selectors" }
2 changes: 1 addition & 1 deletion packages/blitz-dom/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ debug_timer = { workspace = true }
style = { workspace = true }
selectors = { workspace = true }
cssparser = { workspace = true }
style_config = { workspace = true }
static_prefs = { workspace = true }
style_traits = { workspace = true }
style_dom = { workspace = true }
app_units = { workspace = true }
Expand Down
11 changes: 5 additions & 6 deletions packages/blitz-dom/src/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ impl BaseDocument {
println!("Lines:");
for (i, line) in inline_layout.layout.lines().enumerate() {
let metrics = line.metrics();
let x = metrics.inline_min_coord;
let y = metrics.block_min_coord;
let w = metrics.inline_max_coord - metrics.inline_min_coord;
let h = metrics.block_max_coord - metrics.block_min_coord;
let x = metrics.offset;
let y = metrics.min_coord;
let w = metrics.advance;
let h = metrics.max_coord - metrics.min_coord;
println!("Line {i}: x:{x} y:{y} width:{w} height:{h}");
for item in line.items() {
print!(" ");
Expand All @@ -63,8 +63,7 @@ impl BaseDocument {
)
}
PositionedLayoutItem::InlineBox(ibox) => print!(
"BOX {:?} (id: {} x: {} y: {} w: {}, h: {})",
ibox.kind,
"BOX (id: {} x: {} y: {} w: {}, h: {})",
ibox.id,
ibox.x.round(),
ibox.y.round(),
Expand Down
101 changes: 84 additions & 17 deletions packages/blitz-dom/src/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ use std::time::Instant;
use style::Atom;
use style::animation::DocumentAnimationSet;
use style::attr::{AttrIdentifier, AttrValue};
use style::data::{ElementData as StyloElementData, ElementStyles};
use style::data::ElementStyles;
use style::media_queries::MediaType;
use style::properties::ComputedValues;
use style::properties::style_structs::Font;
Expand All @@ -52,7 +52,8 @@ use style::values::GenericAtomIdent;
use style::values::computed::Overflow;
use style::{
dom::{TDocument, TNode},
media_queries::{Device, MediaList},
device::Device,
media_queries::MediaList,
selector_parser::SnapshotMap,
shared_lock::{SharedRwLock, StylesheetGuards},
stylesheets::{AllowImportRules, DocumentStyleSheet, Origin, Stylesheet},
Expand Down Expand Up @@ -264,6 +265,8 @@ pub struct BaseDocument {
pub(crate) changed_nodes: HashSet<usize>,
/// Set of changed nodes for updating the accessibility tree
pub(crate) deferred_construction_nodes: Vec<ConstructionTask>,
/// Node IDs of all position:sticky elements, for efficient recomputation on scroll
pub(crate) sticky_nodes: Vec<usize>,

/// Cache of loaded images, keyed by URL. Allows reusing images across multiple
/// elements without re-fetching from the network.
Expand Down Expand Up @@ -340,12 +343,10 @@ impl BaseDocument {
let font_ctx = Arc::new(Mutex::new(font_ctx));

// Make sure we turn on stylo features *before* creating the Stylist
style_config::set_bool("layout.flexbox.enabled", true);
style_config::set_bool("layout.grid.enabled", true);
style_config::set_bool("layout.legacy_layout", true);
style_config::set_bool("layout.unimplemented", true);
style_config::set_bool("layout.columns.enabled", true);
style_config::set_i32("layout.threads", -1);
static_prefs::set_pref!("layout.grid.enabled", true);
static_prefs::set_pref!("layout.unimplemented", true);
static_prefs::set_pref!("layout.columns.enabled", true);
static_prefs::set_pref!("layout.threads", -1);

let viewport = config.viewport.unwrap_or_default();
let device = make_device(&viewport, font_ctx.clone());
Expand Down Expand Up @@ -408,6 +409,7 @@ impl BaseDocument {
sub_document_nodes: HashSet::new(),
changed_nodes: HashSet::new(),
deferred_construction_nodes: Vec::new(),
sticky_nodes: Vec::new(),
image_cache: HashMap::new(),
pending_images: HashMap::new(),
pending_critical_resources: HashSet::new(),
Expand Down Expand Up @@ -438,17 +440,18 @@ impl BaseDocument {
}

// Stylo data on the root node container is needed to render the node
let stylo_element_data = StyloElementData {
styles: ElementStyles {
let wrapper = style::data::ElementDataWrapper::default();
{
let mut stylo_element_data = wrapper.borrow_mut();
stylo_element_data.styles = ElementStyles {
primary: Some(
ComputedValues::initial_values_with_font_override(Font::initial_values())
.to_arc(),
),
..Default::default()
},
..Default::default()
};
*doc.root_node().stylo_element_data.borrow_mut() = Some(stylo_element_data);
};
}
doc.root_node().stylo_element_data.set(wrapper);

doc
}
Expand Down Expand Up @@ -1093,7 +1096,7 @@ impl BaseDocument {
cb(&mut self.nodes[node_id]);
}

// Takes (x, y) co-ordinates (relative to the )
// Takes (x, y) co-ordinates (page coordinates, i.e. viewport + scroll offset)
pub fn hit(&self, x: f32, y: f32) -> Option<HitResult> {
if TDocument::as_node(&&self.nodes[0])
.first_element_child()
Expand All @@ -1104,9 +1107,67 @@ impl BaseDocument {
return None;
}

// Fixed-position elements are painted at viewport-relative positions (scroll-compensated),
// but hit() receives page coordinates (viewport + scroll). Test fixed children first
// with viewport coordinates so they can be hit correctly when the page is scrolled.
if let Some(hit) = self.hit_fixed_children(x, y) {
return Some(hit);
}

self.root_element().hit(x, y)
}

/// Test fixed-position children of the root element using viewport coordinates.
/// Fixed elements are painted at viewport-relative positions, so hit testing them
/// requires subtracting the viewport scroll from page coordinates.
fn hit_fixed_children(&self, page_x: f32, page_y: f32) -> Option<HitResult> {
use style::properties::generated::longhands::position::computed_value::T as Position;

let root = self.root_element();
let root_id = root.id;
let vx = page_x - self.viewport_scroll.x as f32;
let vy = page_y - self.viewport_scroll.y as f32;

// Helper closure to test a single child node
let test_child = |node_id: usize, offset_x: f32, offset_y: f32| -> Option<HitResult> {
let child = &self.nodes[node_id];
if child.css_position == Position::Fixed && child.layout_parent.get() == Some(root_id) {
child.hit(vx - offset_x, vy - offset_y)
} else {
None
}
};

// Positive z_index hoisted children (highest priority, painted last)
if let Some(hoisted) = &root.stacking_context {
for hc in hoisted.pos_z_hoisted_children().rev() {
if let Some(hit) = test_child(hc.node_id, hc.position.x, hc.position.y) {
return Some(hit);
}
}
}

// Regular paint children
if let Some(children) = &*root.paint_children.borrow() {
for &child_id in children.iter().rev() {
if let Some(hit) = test_child(child_id, 0.0, 0.0) {
return Some(hit);
}
}
}

// Negative z_index hoisted children
if let Some(hoisted) = &root.stacking_context {
for hc in hoisted.neg_z_hoisted_children().rev() {
if let Some(hit) = test_child(hc.node_id, hc.position.x, hc.position.y) {
return Some(hit);
}
}
}

None
}

pub fn focus_next_node(&mut self) -> Option<usize> {
let focussed_node_id = self.get_focussed_node_id()?;
let id = self.next_node(&self.nodes[focussed_node_id], |node| node.is_focussable())?;
Expand Down Expand Up @@ -1474,7 +1535,9 @@ impl BaseDocument {
}

pub fn scroll_viewport_by(&mut self, x: f64, y: f64) {
self.scroll_viewport_by_has_changed(x, y);
if self.scroll_viewport_by_has_changed(x, y) {
self.recompute_sticky_offsets();
}
}

/// Scroll the viewport by the given values
Expand Down Expand Up @@ -1504,11 +1567,15 @@ impl BaseDocument {
scroll_y: f64,
dispatch_event: &mut dyn FnMut(DomEvent),
) -> bool {
if let Some(anchor_node_id) = anchor_node_id {
let changed = if let Some(anchor_node_id) = anchor_node_id {
self.scroll_node_by_has_changed(anchor_node_id, scroll_x, scroll_y, dispatch_event)
} else {
self.scroll_viewport_by_has_changed(scroll_x, scroll_y)
};
if changed {
self.recompute_sticky_offsets();
}
changed
}

pub fn viewport_scroll(&self) -> crate::Point<f64> {
Expand Down
2 changes: 1 addition & 1 deletion packages/blitz-dom/src/font_metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use skrifa::MetadataProvider as _;
use skrifa::charmap::Charmap;
use style::properties::style_structs::Font as FontStyles;
use style::{
device::servo::FontMetricsProvider,
font_metrics::FontMetrics,
servo::media_queries::FontMetricsProvider,
values::computed::{CSSPixelLength, font::QueryFontMetricsFlags},
};

Expand Down
Loading
Loading