зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1623792 - Pt 8 - Add IS_IDENTITY to spatial node flags. r=jnicol
Add a new flag for spatial nodes that identifies if the spatial node is guaranteed to be identity (no transformation at all) for the entirety of the scene (i.e. either a fixed identity reference frame or a redundant scroll frame). Although not used yet, this will be useful in future to help remove clips during scene building that can't possibly affect the content rendering no matter what occurs during frame building. At the same time, port the other bool fields in spatial node into a single bitflags. Differential Revision: https://phabricator.services.mozilla.com/D84957
This commit is contained in:
Родитель
90071d7b7c
Коммит
bfe5060361
|
@ -530,7 +530,7 @@ impl FrameBuilder {
|
|||
let spatial_node = &scene
|
||||
.spatial_tree
|
||||
.spatial_nodes[spatial_node_index.0 as usize];
|
||||
spatial_node.is_ancestor_or_self_zooming
|
||||
spatial_node.is_ancestor_or_self_zooming()
|
||||
});
|
||||
|
||||
let mut composite_state = CompositeState::new(
|
||||
|
|
|
@ -4677,7 +4677,7 @@ impl PicturePrimitive {
|
|||
/// change in zoom level, as that would be too expensive.
|
||||
pub fn get_raster_space(&self, spatial_tree: &SpatialTree) -> RasterSpace {
|
||||
let spatial_node = &spatial_tree.spatial_nodes[self.spatial_node_index.0 as usize];
|
||||
if spatial_node.is_ancestor_or_self_zooming {
|
||||
if spatial_node.is_ancestor_or_self_zooming() {
|
||||
let scale_factors = spatial_tree
|
||||
.get_relative_transform(self.spatial_node_index, ROOT_SPATIAL_NODE_INDEX)
|
||||
.scale_factors();
|
||||
|
@ -6025,7 +6025,7 @@ impl PicturePrimitive {
|
|||
let spatial_node = &frame_context
|
||||
.spatial_tree
|
||||
.spatial_nodes[cluster.spatial_node_index.0 as usize];
|
||||
if !spatial_node.invertible {
|
||||
if !spatial_node.is_invertible() {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -616,8 +616,8 @@ impl Document {
|
|||
let node = self.scene.spatial_tree.spatial_nodes.iter_mut()
|
||||
.find(|node| node.is_transform_bound_to_property(animation_id));
|
||||
if let Some(node) = node {
|
||||
if node.is_async_zooming != is_zooming {
|
||||
node.is_async_zooming = is_zooming;
|
||||
if node.is_async_zooming() != is_zooming {
|
||||
node.set_async_zooming(is_zooming);
|
||||
self.frame_is_valid = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,29 @@ pub enum SpatialNodeType {
|
|||
ReferenceFrame(ReferenceFrameInfo),
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Bits of pre-calculated information about a given spatial node.
|
||||
pub struct SpatialNodeFlags : u32 {
|
||||
/// True if this node is transformed by an invertible transform. If not, display items
|
||||
/// transformed by this node will not be displayed and display items not transformed by this
|
||||
/// node will not be clipped by clips that are transformed by this node.
|
||||
const IS_INVERTIBLE = 1;
|
||||
|
||||
/// Whether this specific node is currently being async zoomed.
|
||||
/// Should be set when a SetIsTransformAsyncZooming FrameMsg is received.
|
||||
const IS_ASYNC_ZOOMING = 2;
|
||||
|
||||
/// Whether this node or any of its ancestors is being pinch zoomed.
|
||||
/// This is calculated in update(). This will be used to decide whether
|
||||
/// to override corresponding picture's raster space as an optimisation.
|
||||
const IS_ANCESTOR_OR_SELF_ZOOMING = 4;
|
||||
|
||||
/// If true, this spatial node and all parents are guaranteed to never introduce
|
||||
/// a transformation. Effectively means that this node implies local space == world space.
|
||||
const IS_IDENTITY = 8;
|
||||
}
|
||||
}
|
||||
|
||||
/// Contains information common among all types of SpatialTree nodes.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SpatialNode {
|
||||
|
@ -60,19 +83,8 @@ pub struct SpatialNode {
|
|||
/// The type of this node and any data associated with that node type.
|
||||
pub node_type: SpatialNodeType,
|
||||
|
||||
/// True if this node is transformed by an invertible transform. If not, display items
|
||||
/// transformed by this node will not be displayed and display items not transformed by this
|
||||
/// node will not be clipped by clips that are transformed by this node.
|
||||
pub invertible: bool,
|
||||
|
||||
/// Whether this specific node is currently being async zoomed.
|
||||
/// Should be set when a SetIsTransformAsyncZooming FrameMsg is received.
|
||||
pub is_async_zooming: bool,
|
||||
|
||||
/// Whether this node or any of its ancestors is being pinch zoomed.
|
||||
/// This is calculated in update(). This will be used to decide whether
|
||||
/// to override corresponding picture's raster space as an optimisation.
|
||||
pub is_ancestor_or_self_zooming: bool,
|
||||
/// Various flags related to the current state of this spatial node.
|
||||
pub flags: SpatialNodeFlags,
|
||||
}
|
||||
|
||||
fn compute_offset_from(
|
||||
|
@ -132,7 +144,11 @@ impl SpatialNode {
|
|||
pipeline_id: PipelineId,
|
||||
parent_index: Option<SpatialNodeIndex>,
|
||||
node_type: SpatialNodeType,
|
||||
is_identity: bool,
|
||||
) -> Self {
|
||||
let mut flags = SpatialNodeFlags::IS_INVERTIBLE;
|
||||
flags.set(SpatialNodeFlags::IS_IDENTITY, is_identity);
|
||||
|
||||
SpatialNode {
|
||||
viewport_transform: ScaleOffset::identity(),
|
||||
content_transform: ScaleOffset::identity(),
|
||||
|
@ -143,12 +159,34 @@ impl SpatialNode {
|
|||
children: Vec::new(),
|
||||
pipeline_id,
|
||||
node_type,
|
||||
invertible: true,
|
||||
is_async_zooming: false,
|
||||
is_ancestor_or_self_zooming: false,
|
||||
flags,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_invertible(&self) -> bool {
|
||||
self.flags.contains(SpatialNodeFlags::IS_INVERTIBLE)
|
||||
}
|
||||
|
||||
pub fn is_async_zooming(&self) -> bool {
|
||||
self.flags.contains(SpatialNodeFlags::IS_ASYNC_ZOOMING)
|
||||
}
|
||||
|
||||
pub fn set_async_zooming(&mut self, value: bool) {
|
||||
self.flags.set(SpatialNodeFlags::IS_ASYNC_ZOOMING, value);
|
||||
}
|
||||
|
||||
pub fn is_ancestor_or_self_zooming(&self) -> bool {
|
||||
self.flags.contains(SpatialNodeFlags::IS_ANCESTOR_OR_SELF_ZOOMING)
|
||||
}
|
||||
|
||||
pub fn set_is_ancestor_or_self_zooming(&mut self, value: bool) {
|
||||
self.flags.set(SpatialNodeFlags::IS_ANCESTOR_OR_SELF_ZOOMING, value);
|
||||
}
|
||||
|
||||
pub fn is_identity(&self) -> bool {
|
||||
self.flags.contains(SpatialNodeFlags::IS_IDENTITY)
|
||||
}
|
||||
|
||||
pub fn new_scroll_frame(
|
||||
pipeline_id: PipelineId,
|
||||
parent_index: SpatialNodeIndex,
|
||||
|
@ -158,21 +196,34 @@ impl SpatialNode {
|
|||
scroll_sensitivity: ScrollSensitivity,
|
||||
frame_kind: ScrollFrameKind,
|
||||
external_scroll_offset: LayoutVector2D,
|
||||
parent_is_identity: bool,
|
||||
) -> Self {
|
||||
let scrollable_size = LayoutSize::new(
|
||||
(content_size.width - frame_rect.size.width).max(0.0),
|
||||
(content_size.height - frame_rect.size.height).max(0.0)
|
||||
);
|
||||
|
||||
// TODO(gw): We might want to consider an epsilon check here, but we
|
||||
// generally only care about the root pipeline scroll frames,
|
||||
// which are fixed as zero.
|
||||
let is_identity = scrollable_size == LayoutSize::zero();
|
||||
|
||||
let node_type = SpatialNodeType::ScrollFrame(ScrollFrameInfo::new(
|
||||
*frame_rect,
|
||||
scroll_sensitivity,
|
||||
LayoutSize::new(
|
||||
(content_size.width - frame_rect.size.width).max(0.0),
|
||||
(content_size.height - frame_rect.size.height).max(0.0)
|
||||
),
|
||||
scrollable_size,
|
||||
external_id,
|
||||
frame_kind,
|
||||
external_scroll_offset,
|
||||
)
|
||||
);
|
||||
|
||||
Self::new(pipeline_id, Some(parent_index), node_type)
|
||||
Self::new(
|
||||
pipeline_id,
|
||||
Some(parent_index),
|
||||
node_type,
|
||||
parent_is_identity && is_identity,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_reference_frame(
|
||||
|
@ -182,7 +233,19 @@ impl SpatialNode {
|
|||
kind: ReferenceFrameKind,
|
||||
origin_in_parent_reference_frame: LayoutVector2D,
|
||||
pipeline_id: PipelineId,
|
||||
parent_is_identity: bool,
|
||||
) -> Self {
|
||||
let is_identity = match source_transform {
|
||||
PropertyBinding::Value(m) => {
|
||||
// TODO(gw): We might want to consider an epsilon check here, but we
|
||||
// generally only care about the root pipeline reference frames,
|
||||
// which are fixed as zero.
|
||||
m == LayoutTransform::identity()
|
||||
}
|
||||
PropertyBinding::Binding(..) => {
|
||||
false
|
||||
}
|
||||
};
|
||||
let info = ReferenceFrameInfo {
|
||||
transform_style,
|
||||
source_transform,
|
||||
|
@ -190,7 +253,12 @@ impl SpatialNode {
|
|||
origin_in_parent_reference_frame,
|
||||
invertible: true,
|
||||
};
|
||||
Self::new(pipeline_id, parent_index, SpatialNodeType::ReferenceFrame(info))
|
||||
Self::new(
|
||||
pipeline_id,
|
||||
parent_index,
|
||||
SpatialNodeType::ReferenceFrame(info),
|
||||
parent_is_identity && is_identity,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn new_sticky_frame(
|
||||
|
@ -198,7 +266,12 @@ impl SpatialNode {
|
|||
sticky_frame_info: StickyFrameInfo,
|
||||
pipeline_id: PipelineId,
|
||||
) -> Self {
|
||||
Self::new(pipeline_id, Some(parent_index), SpatialNodeType::StickyFrame(sticky_frame_info))
|
||||
Self::new(
|
||||
pipeline_id,
|
||||
Some(parent_index),
|
||||
SpatialNodeType::StickyFrame(sticky_frame_info),
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn add_child(&mut self, child: SpatialNodeIndex) {
|
||||
|
@ -259,7 +332,7 @@ impl SpatialNode {
|
|||
&mut self,
|
||||
state: &TransformUpdateState,
|
||||
) {
|
||||
self.invertible = false;
|
||||
self.flags.remove(SpatialNodeFlags::IS_INVERTIBLE);
|
||||
self.viewport_transform = ScaleOffset::identity();
|
||||
self.content_transform = ScaleOffset::identity();
|
||||
self.coordinate_system_id = state.current_coordinate_system_id;
|
||||
|
@ -289,10 +362,10 @@ impl SpatialNode {
|
|||
};
|
||||
|
||||
let is_parent_zooming = match self.parent {
|
||||
Some(parent) => previous_spatial_nodes[parent.0 as usize].is_ancestor_or_self_zooming,
|
||||
Some(parent) => previous_spatial_nodes[parent.0 as usize].is_ancestor_or_self_zooming(),
|
||||
_ => false,
|
||||
};
|
||||
self.is_ancestor_or_self_zooming = self.is_async_zooming | is_parent_zooming;
|
||||
self.set_is_ancestor_or_self_zooming(self.is_async_zooming() || is_parent_zooming);
|
||||
|
||||
// If this node is a reference frame, we check if it has a non-invertible matrix.
|
||||
// For non-reference-frames we assume that they will produce only additional
|
||||
|
@ -301,7 +374,7 @@ impl SpatialNode {
|
|||
SpatialNodeType::ReferenceFrame(info) if !info.invertible => {
|
||||
self.mark_uninvertible(state);
|
||||
}
|
||||
_ => self.invertible = true,
|
||||
_ => self.flags.insert(SpatialNodeFlags::IS_INVERTIBLE),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -425,7 +498,7 @@ impl SpatialNode {
|
|||
self.coordinate_system_id = state.current_coordinate_system_id;
|
||||
self.viewport_transform = cs_scale_offset;
|
||||
self.content_transform = cs_scale_offset;
|
||||
self.invertible = info.invertible;
|
||||
self.flags.set(SpatialNodeFlags::IS_INVERTIBLE, info.invertible);
|
||||
}
|
||||
_ => {
|
||||
// We calculate this here to avoid a double-borrow later.
|
||||
|
@ -572,7 +645,7 @@ impl SpatialNode {
|
|||
}
|
||||
|
||||
pub fn prepare_state_for_children(&self, state: &mut TransformUpdateState) {
|
||||
if !self.invertible {
|
||||
if !self.is_invertible() {
|
||||
state.invertible = false;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -558,6 +558,8 @@ impl SpatialTree {
|
|||
frame_kind: ScrollFrameKind,
|
||||
external_scroll_offset: LayoutVector2D,
|
||||
) -> SpatialNodeIndex {
|
||||
let parent_is_identity = self.spatial_nodes[parent_index.0 as usize].is_identity();
|
||||
|
||||
let node = SpatialNode::new_scroll_frame(
|
||||
pipeline_id,
|
||||
parent_index,
|
||||
|
@ -567,6 +569,7 @@ impl SpatialTree {
|
|||
scroll_sensitivity,
|
||||
frame_kind,
|
||||
external_scroll_offset,
|
||||
parent_is_identity,
|
||||
);
|
||||
self.add_spatial_node(node)
|
||||
}
|
||||
|
@ -580,6 +583,9 @@ impl SpatialTree {
|
|||
origin_in_parent_reference_frame: LayoutVector2D,
|
||||
pipeline_id: PipelineId,
|
||||
) -> SpatialNodeIndex {
|
||||
let parent_is_identity = parent_index.map_or(true, |parent_index| {
|
||||
self.spatial_nodes[parent_index.0 as usize].is_identity()
|
||||
});
|
||||
let node = SpatialNode::new_reference_frame(
|
||||
parent_index,
|
||||
transform_style,
|
||||
|
@ -587,6 +593,7 @@ impl SpatialTree {
|
|||
kind,
|
||||
origin_in_parent_reference_frame,
|
||||
pipeline_id,
|
||||
parent_is_identity,
|
||||
);
|
||||
self.add_spatial_node(node)
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче