Skip to main content

engine_observables_api/
fragment.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! Laid-out geometry queries — hit-testing, box-model lookup,
6//! anchor-to-fragments, selection rects.
7//!
8//! Cf. Hekate doc §"Layout/Fragment Plane". The trait is the
9//! permanent ABI; internal plane storage (IndexVec / FxHashMap /
10//! whatever) stays each lane's implementation detail.
11
12use malloc_size_of_derive::MallocSizeOf;
13use serde::{Deserialize, Serialize};
14
15use crate::types::{Point, Rect, SourceNodeId, SourceRange};
16
17/// Common-minimum laid-out-geometry queries. Each lane that has a
18/// layout phase implements this. Internal `FragmentId` type is per-
19/// lane (opaque to consumers — only used as a map key).
20pub trait FragmentQuery {
21    /// Per-lane opaque fragment identity. Consumers compare for
22    /// equality and use as map keys.
23    type FragmentId: Copy + Eq + std::hash::Hash;
24
25    /// Epoch — invalidated on any relayout. Consumers cache against
26    /// this; the value rolls when the plane regenerates.
27    fn generation_id(&self) -> u64;
28
29    /// Hit-test at a viewport point. Returns the topmost fragment
30    /// hit (paint-order semantics), or `None` if the point falls
31    /// outside any fragment.
32    fn hit_test(&self, point: Point) -> Option<FragmentHit<Self::FragmentId>>;
33
34    /// CSS box-model for a source node. None if the node has no
35    /// fragment (e.g., `display: none`, or before layout completes).
36    fn box_model(&self, source_id: SourceNodeId) -> Option<BoxModel>;
37
38    /// Fragments under a named anchor (e.g., `#section-2`).
39    fn fragments_for_anchor<'a>(
40        &'a self,
41        anchor: &str,
42    ) -> Box<dyn Iterator<Item = Self::FragmentId> + 'a>;
43
44    /// Reverse mapping: fragment → source span. Used by selection,
45    /// "what node was here," and Apparatus.
46    fn text_range_for_fragment(&self, fragment: Self::FragmentId) -> Option<SourceRange>;
47
48    /// Selection → screen rects. Multi-rect because a selection can
49    /// span lines or wrap; consumers (selection-highlight painter)
50    /// draw one rect per returned entry.
51    fn rects_for_selection(&self, range: SourceRange) -> Vec<Rect>;
52}
53
54/// What `hit_test` returns. Carries the lane's fragment id, the
55/// containing source node, and the local hit point inside the
56/// fragment (so consumers can drive caret positioning without
57/// re-walking).
58#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize)]
59pub struct FragmentHit<FragmentId: Copy> {
60    pub fragment: FragmentId,
61    pub source_node: SourceNodeId,
62    /// Hit point in the fragment's local space (origin at the
63    /// fragment's top-left).
64    pub local_point: Point,
65}
66
67/// CSS box-model for one source node's fragment. The four nested
68/// rectangles — content / padding / border / margin — are each in
69/// viewport coordinates. Consumers wanting `getBoundingClientRect`
70/// shape read `border` (the border-edge rect).
71#[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize)]
72pub struct BoxModel {
73    /// Content-box rect (inside padding).
74    pub content: Rect,
75    /// Padding-box rect (between border and content).
76    pub padding: Rect,
77    /// Border-box rect (between margin and padding). Matches
78    /// `getBoundingClientRect()` in DOM semantics.
79    pub border: Rect,
80    /// Margin-box rect (outermost).
81    pub margin: Rect,
82}