mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Bug 1477970 - Update webrender to commit 8a4fe66528aa362721e4048aac3cd5abf7faaf2c. r=jrmuizel
MozReview-Commit-ID: H40i6i2LmAl --HG-- extra : rebase_source : 5bd5ea3be3463b3f91a2e64da4e2c99c55cecd45
This commit is contained in:
parent
70da238a9a
commit
78157f60ff
@ -497,6 +497,9 @@ impl AlphaBatchBuilder {
|
||||
// Z axis is directed at the screen, `sort` is ascending, and we need back-to-front order.
|
||||
for poly in splitter.sort(vec3(0.0, 0.0, 1.0)) {
|
||||
let prim_index = PrimitiveIndex(poly.anchor);
|
||||
if cfg!(debug_assertions) && ctx.prim_store.chase_id == Some(prim_index) {
|
||||
println!("\t\tsplit polygon {:?}", poly.points);
|
||||
}
|
||||
debug!("process sorted poly {:?} {:?}", prim_index, poly.points);
|
||||
let pp = &poly.points;
|
||||
let gpu_blocks = [
|
||||
@ -654,14 +657,18 @@ impl AlphaBatchBuilder {
|
||||
transform_id,
|
||||
};
|
||||
|
||||
if cfg!(debug_assertions) && ctx.prim_store.chase_id == Some(prim_index) {
|
||||
println!("\ttask target {:?}", self.target_rect);
|
||||
println!("\t{:?}", prim_header);
|
||||
}
|
||||
|
||||
match prim_metadata.prim_kind {
|
||||
PrimitiveKind::Brush => {
|
||||
let brush = &ctx.prim_store.cpu_brushes[prim_metadata.cpu_prim_index.0];
|
||||
|
||||
match brush.kind {
|
||||
BrushKind::Picture { pic_index, .. } => {
|
||||
let picture =
|
||||
&ctx.prim_store.pictures[pic_index.0];
|
||||
let picture = &ctx.prim_store.pictures[pic_index.0];
|
||||
|
||||
// If this picture is participating in a 3D rendering context,
|
||||
// then don't add it to any batches here. Instead, create a polygon
|
||||
@ -1056,8 +1063,13 @@ impl AlphaBatchBuilder {
|
||||
ctx.resource_cache,
|
||||
gpu_cache,
|
||||
deferred_resolves,
|
||||
ctx.prim_store.chase_id == Some(prim_index),
|
||||
) {
|
||||
let prim_header_index = prim_headers.push(&prim_header, user_data);
|
||||
if cfg!(debug_assertions) && ctx.prim_store.chase_id == Some(prim_index) {
|
||||
println!("\t{:?} {:?}, task relative bounds {:?}",
|
||||
batch_kind, prim_header_index, task_relative_bounding_rect);
|
||||
}
|
||||
|
||||
self.add_brush_to_batch(
|
||||
brush,
|
||||
@ -1385,6 +1397,7 @@ impl BrushPrimitive {
|
||||
resource_cache: &ResourceCache,
|
||||
gpu_cache: &mut GpuCache,
|
||||
deferred_resolves: &mut Vec<DeferredResolve>,
|
||||
is_chased: bool,
|
||||
) -> Option<(BrushBatchKind, BatchTextures, [i32; 3])> {
|
||||
match self.kind {
|
||||
BrushKind::Image { request, ref source, .. } => {
|
||||
@ -1406,6 +1419,9 @@ impl BrushPrimitive {
|
||||
resource_cache.get_texture_cache_item(&rt_cache_entry.handle)
|
||||
}
|
||||
};
|
||||
if cfg!(debug_assertions) && is_chased {
|
||||
println!("\tsource {:?}", cache_item);
|
||||
}
|
||||
|
||||
if cache_item.texture_id == SourceTexture::Invalid {
|
||||
None
|
||||
@ -1751,7 +1767,7 @@ impl ClipBatcher {
|
||||
) {
|
||||
let instance = ClipMaskInstance {
|
||||
render_task_address: task_address,
|
||||
transform_id: TransformPaletteId::identity(),
|
||||
transform_id: TransformPaletteId::IDENTITY,
|
||||
segment: 0,
|
||||
clip_data_address,
|
||||
resource_address: GpuCacheAddress::invalid(),
|
||||
@ -1772,16 +1788,14 @@ impl ClipBatcher {
|
||||
) {
|
||||
let mut coordinate_system_id = coordinate_system_id;
|
||||
for work_item in clips.iter() {
|
||||
let info = clip_store.get(work_item.clip_sources_index);
|
||||
let instance = ClipMaskInstance {
|
||||
render_task_address: task_address,
|
||||
transform_id: transforms.get_id(work_item.spatial_node_index),
|
||||
transform_id: transforms.get_id(info.spatial_node_index),
|
||||
segment: 0,
|
||||
clip_data_address: GpuCacheAddress::invalid(),
|
||||
resource_address: GpuCacheAddress::invalid(),
|
||||
};
|
||||
let info = clip_store
|
||||
.get_opt(&work_item.clip_sources)
|
||||
.expect("bug: clip handle should be valid");
|
||||
|
||||
for &(ref source, ref handle) in &info.clips {
|
||||
let gpu_address = gpu_cache.get_address(handle);
|
||||
|
@ -9,22 +9,51 @@ use border::{ensure_no_corner_overlap};
|
||||
use box_shadow::{BLUR_SAMPLE_SCALE, BoxShadowClipSource, BoxShadowCacheKey};
|
||||
use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId, SpatialNodeIndex};
|
||||
use ellipse::Ellipse;
|
||||
use freelist::{FreeList, FreeListHandle, WeakFreeListHandle};
|
||||
use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks};
|
||||
use gpu_types::BoxShadowStretchMode;
|
||||
use prim_store::{ClipData, ImageMaskData};
|
||||
use render_task::to_cache_size;
|
||||
use resource_cache::{ImageRequest, ResourceCache};
|
||||
use util::{LayoutToWorldFastTransform, MaxRect, calculate_screen_bounding_rect};
|
||||
use util::{extract_inner_rect_safe, pack_as_float};
|
||||
use util::{extract_inner_rect_safe, pack_as_float, recycle_vec};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ClipStoreMarker {}
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct ClipSourcesIndex(usize);
|
||||
|
||||
pub type ClipStore = FreeList<ClipSources, ClipStoreMarker>;
|
||||
pub type ClipSourcesHandle = FreeListHandle<ClipStoreMarker>;
|
||||
pub type ClipSourcesWeakHandle = WeakFreeListHandle<ClipStoreMarker>;
|
||||
pub struct ClipStore {
|
||||
clip_sources: Vec<ClipSources>,
|
||||
}
|
||||
|
||||
impl ClipStore {
|
||||
pub fn new() -> ClipStore {
|
||||
ClipStore {
|
||||
clip_sources: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn recycle(self) -> ClipStore {
|
||||
ClipStore {
|
||||
clip_sources: recycle_vec(self.clip_sources),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, clip_sources: ClipSources) -> ClipSourcesIndex {
|
||||
let index = ClipSourcesIndex(self.clip_sources.len());
|
||||
self.clip_sources.push(clip_sources);
|
||||
index
|
||||
}
|
||||
|
||||
pub fn get(&self, index: ClipSourcesIndex) -> &ClipSources {
|
||||
&self.clip_sources[index.0]
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, index: ClipSourcesIndex) -> &mut ClipSources {
|
||||
&mut self.clip_sources[index.0]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LineDecorationClipSource {
|
||||
@ -91,28 +120,6 @@ pub enum ClipSource {
|
||||
LineDecoration(LineDecorationClipSource),
|
||||
}
|
||||
|
||||
impl From<ClipRegion> for ClipSources {
|
||||
fn from(region: ClipRegion) -> ClipSources {
|
||||
let mut clips = Vec::new();
|
||||
|
||||
if let Some(info) = region.image_mask {
|
||||
clips.push(ClipSource::Image(info));
|
||||
}
|
||||
|
||||
clips.push(ClipSource::Rectangle(region.main, ClipMode::Clip));
|
||||
|
||||
for complex in region.complex_clips {
|
||||
clips.push(ClipSource::new_rounded_rect(
|
||||
complex.rect,
|
||||
complex.radii,
|
||||
complex.mode,
|
||||
));
|
||||
}
|
||||
|
||||
ClipSources::new(clips)
|
||||
}
|
||||
}
|
||||
|
||||
impl ClipSource {
|
||||
pub fn new_rounded_rect(
|
||||
rect: LayoutRect,
|
||||
@ -280,10 +287,14 @@ pub struct ClipSources {
|
||||
pub local_outer_rect: Option<LayoutRect>,
|
||||
pub only_rectangular_clips: bool,
|
||||
pub has_image_or_line_decoration_clip: bool,
|
||||
pub spatial_node_index: SpatialNodeIndex,
|
||||
}
|
||||
|
||||
impl ClipSources {
|
||||
pub fn new(clips: Vec<ClipSource>) -> Self {
|
||||
pub fn new(
|
||||
clips: Vec<ClipSource>,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
) -> Self {
|
||||
let (local_inner_rect, local_outer_rect) = Self::calculate_inner_and_outer_rects(&clips);
|
||||
|
||||
let has_image_or_line_decoration_clip =
|
||||
@ -301,9 +312,33 @@ impl ClipSources {
|
||||
local_outer_rect,
|
||||
only_rectangular_clips,
|
||||
has_image_or_line_decoration_clip,
|
||||
spatial_node_index,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_region(
|
||||
region: ClipRegion,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
) -> ClipSources {
|
||||
let mut clips = Vec::new();
|
||||
|
||||
if let Some(info) = region.image_mask {
|
||||
clips.push(ClipSource::Image(info));
|
||||
}
|
||||
|
||||
clips.push(ClipSource::Rectangle(region.main, ClipMode::Clip));
|
||||
|
||||
for complex in region.complex_clips {
|
||||
clips.push(ClipSource::new_rounded_rect(
|
||||
complex.rect,
|
||||
complex.radii,
|
||||
complex.mode,
|
||||
));
|
||||
}
|
||||
|
||||
ClipSources::new(clips, spatial_node_index)
|
||||
}
|
||||
|
||||
pub fn clips(&self) -> &[(ClipSource, GpuCacheHandle)] {
|
||||
&self.clips
|
||||
}
|
||||
@ -647,8 +682,7 @@ impl Iterator for ClipChainNodeIter {
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct ClipWorkItem {
|
||||
pub spatial_node_index: SpatialNodeIndex,
|
||||
pub clip_sources: ClipSourcesWeakHandle,
|
||||
pub clip_sources_index: ClipSourcesIndex,
|
||||
pub coordinate_system_id: CoordinateSystemId,
|
||||
}
|
||||
|
||||
|
@ -3,19 +3,16 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use api::DevicePixelScale;
|
||||
use clip::{ClipChain, ClipChainNode, ClipSourcesHandle, ClipStore, ClipWorkItem};
|
||||
use clip_scroll_tree::{ClipChainIndex, SpatialNodeIndex};
|
||||
use clip::{ClipChain, ClipChainNode, ClipSourcesIndex, ClipStore, ClipWorkItem};
|
||||
use clip_scroll_tree::{ClipChainIndex};
|
||||
use gpu_cache::GpuCache;
|
||||
use resource_cache::ResourceCache;
|
||||
use spatial_node::SpatialNode;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ClipNode {
|
||||
/// The node that determines how this clip node is positioned.
|
||||
pub spatial_node: SpatialNodeIndex,
|
||||
|
||||
/// A handle to this clip nodes clips in the ClipStore.
|
||||
pub handle: Option<ClipSourcesHandle>,
|
||||
pub clip_sources_index: ClipSourcesIndex,
|
||||
|
||||
/// An index to a ClipChain defined by this ClipNode's hiearchy in the display
|
||||
/// list.
|
||||
@ -31,35 +28,18 @@ pub struct ClipNode {
|
||||
}
|
||||
|
||||
impl ClipNode {
|
||||
const EMPTY: ClipNode = ClipNode {
|
||||
spatial_node: SpatialNodeIndex(0),
|
||||
handle: None,
|
||||
clip_chain_index: ClipChainIndex::NO_CLIP,
|
||||
parent_clip_chain_index: ClipChainIndex::NO_CLIP,
|
||||
clip_chain_node: None,
|
||||
};
|
||||
|
||||
pub fn empty() -> ClipNode {
|
||||
ClipNode::EMPTY
|
||||
}
|
||||
|
||||
pub fn update(
|
||||
&mut self,
|
||||
spatial_node: &SpatialNode,
|
||||
device_pixel_scale: DevicePixelScale,
|
||||
clip_store: &mut ClipStore,
|
||||
resource_cache: &mut ResourceCache,
|
||||
gpu_cache: &mut GpuCache,
|
||||
clip_chains: &mut [ClipChain],
|
||||
spatial_nodes: &[SpatialNode],
|
||||
) {
|
||||
let (clip_sources, weak_handle) = match self.handle {
|
||||
Some(ref handle) => (clip_store.get_mut(handle), handle.weak()),
|
||||
None => {
|
||||
warn!("Tried to process an empty clip node");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let clip_sources = clip_store.get_mut(self.clip_sources_index);
|
||||
clip_sources.update(gpu_cache, resource_cache, device_pixel_scale);
|
||||
let spatial_node = &spatial_nodes[clip_sources.spatial_node_index.0];
|
||||
|
||||
let (screen_inner_rect, screen_outer_rect) = clip_sources.get_screen_bounds(
|
||||
&spatial_node.world_content_transform,
|
||||
@ -77,8 +57,7 @@ impl ClipNode {
|
||||
|
||||
let new_node = ClipChainNode {
|
||||
work_item: ClipWorkItem {
|
||||
spatial_node_index: self.spatial_node,
|
||||
clip_sources: weak_handle,
|
||||
clip_sources_index: self.clip_sources_index,
|
||||
coordinate_system_id: spatial_node.coordinate_system_id,
|
||||
},
|
||||
local_clip_rect: spatial_node
|
||||
|
@ -5,7 +5,7 @@
|
||||
use api::{DeviceIntRect, DevicePixelScale, ExternalScrollId, LayoutPoint, LayoutRect, LayoutVector2D};
|
||||
use api::{PipelineId, ScrollClamping, ScrollLocation, ScrollNodeState};
|
||||
use api::{LayoutSize, LayoutTransform, PropertyBinding, ScrollSensitivity, WorldPoint};
|
||||
use clip::{ClipChain, ClipSourcesHandle, ClipStore};
|
||||
use clip::{ClipChain, ClipSourcesIndex, ClipStore};
|
||||
use clip_node::ClipNode;
|
||||
use gpu_cache::GpuCache;
|
||||
use gpu_types::TransformPalette;
|
||||
@ -256,14 +256,13 @@ impl ClipScrollTree {
|
||||
);
|
||||
|
||||
for clip_node in &mut self.clip_nodes {
|
||||
let spatial_node = &self.spatial_nodes[clip_node.spatial_node.0];
|
||||
clip_node.update(
|
||||
spatial_node,
|
||||
device_pixel_scale,
|
||||
clip_store,
|
||||
resource_cache,
|
||||
gpu_cache,
|
||||
&mut self.clip_chains,
|
||||
&self.spatial_nodes,
|
||||
);
|
||||
}
|
||||
self.build_clip_chains(screen_rect);
|
||||
@ -355,33 +354,29 @@ impl ClipScrollTree {
|
||||
|
||||
pub fn add_clip_node(
|
||||
&mut self,
|
||||
index: ClipNodeIndex,
|
||||
parent_clip_chain_index: ClipChainIndex,
|
||||
spatial_node: SpatialNodeIndex,
|
||||
handle: ClipSourcesHandle,
|
||||
) -> ClipChainIndex {
|
||||
clip_sources_index: ClipSourcesIndex,
|
||||
) -> (ClipNodeIndex, ClipChainIndex) {
|
||||
let clip_chain_index = self.allocate_clip_chain();
|
||||
let node = ClipNode {
|
||||
parent_clip_chain_index,
|
||||
spatial_node,
|
||||
handle: Some(handle),
|
||||
clip_sources_index,
|
||||
clip_chain_index,
|
||||
clip_chain_node: None,
|
||||
};
|
||||
self.push_clip_node(node, index);
|
||||
clip_chain_index
|
||||
let node_index = self.push_clip_node(node);
|
||||
(node_index, clip_chain_index)
|
||||
}
|
||||
|
||||
pub fn add_scroll_frame(
|
||||
&mut self,
|
||||
index: SpatialNodeIndex,
|
||||
parent_index: SpatialNodeIndex,
|
||||
external_id: Option<ExternalScrollId>,
|
||||
pipeline_id: PipelineId,
|
||||
frame_rect: &LayoutRect,
|
||||
content_size: &LayoutSize,
|
||||
scroll_sensitivity: ScrollSensitivity,
|
||||
) {
|
||||
) -> SpatialNodeIndex {
|
||||
let node = SpatialNode::new_scroll_frame(
|
||||
pipeline_id,
|
||||
parent_index,
|
||||
@ -390,18 +385,17 @@ impl ClipScrollTree {
|
||||
content_size,
|
||||
scroll_sensitivity,
|
||||
);
|
||||
self.add_spatial_node(node, index);
|
||||
self.add_spatial_node(node)
|
||||
}
|
||||
|
||||
pub fn add_reference_frame(
|
||||
&mut self,
|
||||
index: SpatialNodeIndex,
|
||||
parent_index: Option<SpatialNodeIndex>,
|
||||
source_transform: Option<PropertyBinding<LayoutTransform>>,
|
||||
source_perspective: Option<LayoutTransform>,
|
||||
origin_in_parent_reference_frame: LayoutVector2D,
|
||||
pipeline_id: PipelineId,
|
||||
) {
|
||||
) -> SpatialNodeIndex {
|
||||
let node = SpatialNode::new_reference_frame(
|
||||
parent_index,
|
||||
source_transform,
|
||||
@ -409,22 +403,21 @@ impl ClipScrollTree {
|
||||
origin_in_parent_reference_frame,
|
||||
pipeline_id,
|
||||
);
|
||||
self.add_spatial_node(node, index);
|
||||
self.add_spatial_node(node)
|
||||
}
|
||||
|
||||
pub fn add_sticky_frame(
|
||||
&mut self,
|
||||
index: SpatialNodeIndex,
|
||||
parent_index: SpatialNodeIndex,
|
||||
sticky_frame_info: StickyFrameInfo,
|
||||
pipeline_id: PipelineId,
|
||||
) {
|
||||
) -> SpatialNodeIndex {
|
||||
let node = SpatialNode::new_sticky_frame(
|
||||
parent_index,
|
||||
sticky_frame_info,
|
||||
pipeline_id,
|
||||
);
|
||||
self.add_spatial_node(node, index);
|
||||
self.add_spatial_node(node)
|
||||
}
|
||||
|
||||
pub fn add_clip_chain_descriptor(
|
||||
@ -437,47 +430,22 @@ impl ClipScrollTree {
|
||||
index
|
||||
}
|
||||
|
||||
pub fn push_clip_node(&mut self, node: ClipNode, index: ClipNodeIndex) {
|
||||
if index.0 == self.clip_nodes.len() {
|
||||
self.clip_nodes.push(node);
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(empty_node) = self.clip_nodes.get_mut(index.0) {
|
||||
*empty_node = node;
|
||||
return
|
||||
}
|
||||
|
||||
let length_to_reserve = index.0 + 1 - self.clip_nodes.len();
|
||||
self.clip_nodes.reserve_exact(length_to_reserve);
|
||||
|
||||
// We would like to use `Vec::resize` here, but the Clone trait is not supported
|
||||
// for ClipNodes. We can fix this either when support is added for something like
|
||||
// `Vec::resize_default`.
|
||||
let length_to_extend = self.clip_nodes.len() .. index.0;
|
||||
self.clip_nodes.extend(length_to_extend.map(|_| ClipNode::empty()));
|
||||
pub fn push_clip_node(&mut self, node: ClipNode) -> ClipNodeIndex {
|
||||
let index = ClipNodeIndex(self.clip_nodes.len());
|
||||
self.clip_nodes.push(node);
|
||||
index
|
||||
}
|
||||
|
||||
pub fn add_spatial_node(&mut self, node: SpatialNode, index: SpatialNodeIndex) {
|
||||
pub fn add_spatial_node(&mut self, node: SpatialNode) -> SpatialNodeIndex {
|
||||
let index = SpatialNodeIndex(self.spatial_nodes.len());
|
||||
|
||||
// When the parent node is None this means we are adding the root.
|
||||
if let Some(parent_index) = node.parent {
|
||||
self.spatial_nodes[parent_index.0].add_child(index);
|
||||
}
|
||||
|
||||
if index.0 == self.spatial_nodes.len() {
|
||||
self.spatial_nodes.push(node);
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(empty_node) = self.spatial_nodes.get_mut(index.0) {
|
||||
*empty_node = node;
|
||||
return
|
||||
}
|
||||
|
||||
debug_assert!(index.0 > self.spatial_nodes.len() - 1);
|
||||
self.spatial_nodes.resize(index.0, SpatialNode::empty());
|
||||
self.spatial_nodes.push(node);
|
||||
index
|
||||
}
|
||||
|
||||
pub fn discard_frame_state_for_pipeline(&mut self, pipeline_id: PipelineId) {
|
||||
@ -508,7 +476,6 @@ impl ClipScrollTree {
|
||||
pt.new_level(format!("ReferenceFrame {:?}", info.resolved_transform));
|
||||
pt.add_item(format!("index: {:?}", index));
|
||||
}
|
||||
SpatialNodeType::Empty => unreachable!("Empty node remaining in ClipScrollTree."),
|
||||
}
|
||||
|
||||
pt.add_item(format!("world_viewport_transform: {:?}", node.world_viewport_transform));
|
||||
|
@ -13,7 +13,7 @@ use api::{LineOrientation, LineStyle, LocalClip, NinePatchBorderSource, Pipeline
|
||||
use api::{PropertyBinding, ReferenceFrame, RepeatMode, ScrollFrameDisplayItem, ScrollSensitivity};
|
||||
use api::{Shadow, SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect};
|
||||
use api::{TransformStyle, YuvColorSpace, YuvData};
|
||||
use clip::{ClipRegion, ClipSource, ClipSources, ClipStore};
|
||||
use clip::{ClipRegion, ClipSource, ClipSources, ClipSourcesIndex, ClipStore};
|
||||
use clip_scroll_tree::{ClipChainIndex, ClipNodeIndex, ClipScrollTree, SpatialNodeIndex};
|
||||
use euclid::vec2;
|
||||
use frame_builder::{ChasePrimitive, FrameBuilder, FrameBuilderConfig};
|
||||
@ -33,7 +33,7 @@ use resource_cache::{FontInstanceMap, ImageRequest};
|
||||
use scene::{Scene, ScenePipeline, StackingContextHelpers};
|
||||
use scene_builder::{BuiltScene, SceneRequest};
|
||||
use spatial_node::{SpatialNodeType, StickyFrameInfo};
|
||||
use std::{f32, mem, usize};
|
||||
use std::{f32, mem};
|
||||
use tiling::{CompositeOps, ScrollbarPrimitive};
|
||||
use util::{MaxRect, RectHelpers, recycle_vec};
|
||||
|
||||
@ -44,52 +44,20 @@ static DEFAULT_SCROLLBAR_COLOR: ColorF = ColorF {
|
||||
a: 0.6,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct PipelineOffset {
|
||||
pipeline: PipelineId,
|
||||
spatial_offset: usize,
|
||||
clip_offset: usize,
|
||||
}
|
||||
|
||||
/// A data structure that keeps track of mapping between API ClipIds and the indices used
|
||||
/// internally in the ClipScrollTree to avoid having to do HashMap lookups. ClipIdToIndexMapper is
|
||||
/// responsible for mapping both ClipId to ClipChainIndex and ClipId to SpatialNodeIndex. We
|
||||
/// also include two small LRU caches. Currently the caches are small (1 entry), but in the future
|
||||
/// we could use uluru here to do something more involved.
|
||||
/// responsible for mapping both ClipId to ClipChainIndex and ClipId to SpatialNodeIndex.
|
||||
#[derive(Default)]
|
||||
pub struct ClipIdToIndexMapper {
|
||||
/// A map which converts a ClipId for a clipping node or an API-defined ClipChain into
|
||||
/// a ClipChainIndex, which is the index used internally in the ClipScrollTree to
|
||||
/// identify ClipChains.
|
||||
clip_chain_map: FastHashMap<ClipId, ClipChainIndex>,
|
||||
|
||||
/// The last mapped ClipChainIndex, used to avoid having to do lots of consecutive
|
||||
/// HashMap lookups.
|
||||
cached_clip_chain_index: Option<(ClipId, ClipChainIndex)>,
|
||||
|
||||
/// The offset in the ClipScrollTree's array of SpatialNodes and ClipNodes for a particular
|
||||
/// pipeline. This is used to convert ClipIds into SpatialNodeIndex or ClipNodeIndex.
|
||||
pipeline_offsets: FastHashMap<PipelineId, PipelineOffset>,
|
||||
|
||||
/// The last mapped pipeline offset for this mapper. This is used to avoid having to
|
||||
/// consult `pipeline_offsets` repeatedly when flattening the display list.
|
||||
cached_pipeline_offset: Option<PipelineOffset>,
|
||||
|
||||
/// The next available pipeline offset for ClipNodeIndex. When we encounter a pipeline
|
||||
/// we will use this value and increment it by the total number of clip nodes in the
|
||||
/// pipeline's display list.
|
||||
next_available_clip_offset: usize,
|
||||
|
||||
/// The next available pipeline offset for SpatialNodeIndex. When we encounter a pipeline
|
||||
/// we will use this value and increment it by the total number of spatial nodes in the
|
||||
/// pipeline's display list.
|
||||
next_available_spatial_offset: usize,
|
||||
clip_node_map: FastHashMap<ClipId, ClipNodeIndex>,
|
||||
spatial_node_map: FastHashMap<ClipId, SpatialNodeIndex>,
|
||||
}
|
||||
|
||||
impl ClipIdToIndexMapper {
|
||||
pub fn add_clip_chain(&mut self, id: ClipId, index: ClipChainIndex) {
|
||||
debug_assert!(!self.clip_chain_map.contains_key(&id));
|
||||
self.clip_chain_map.insert(id, index);
|
||||
let _old_value = self.clip_chain_map.insert(id, index);
|
||||
debug_assert!(_old_value.is_none());
|
||||
}
|
||||
|
||||
pub fn map_to_parent_clip_chain(&mut self, id: ClipId, parent_id: &ClipId) {
|
||||
@ -97,53 +65,24 @@ impl ClipIdToIndexMapper {
|
||||
self.add_clip_chain(id, parent_chain_index);
|
||||
}
|
||||
|
||||
pub fn get_clip_chain_index(&mut self, id: &ClipId) -> ClipChainIndex {
|
||||
match self.cached_clip_chain_index {
|
||||
Some((cached_id, cached_clip_chain_index)) if cached_id == *id =>
|
||||
return cached_clip_chain_index,
|
||||
_ => {}
|
||||
}
|
||||
pub fn map_spatial_node(&mut self, id: ClipId, index: SpatialNodeIndex) {
|
||||
let _old_value = self.spatial_node_map.insert(id, index);
|
||||
debug_assert!(_old_value.is_none());
|
||||
}
|
||||
|
||||
pub fn map_clip_node(&mut self, id: ClipId, index: ClipNodeIndex) {
|
||||
let _old_value = self.clip_node_map.insert(id, index);
|
||||
debug_assert!(_old_value.is_none());
|
||||
}
|
||||
|
||||
pub fn get_clip_chain_index(&self, id: &ClipId) -> ClipChainIndex {
|
||||
self.clip_chain_map[id]
|
||||
}
|
||||
|
||||
pub fn get_clip_chain_index_and_cache_result(&mut self, id: &ClipId) -> ClipChainIndex {
|
||||
let index = self.get_clip_chain_index(id);
|
||||
self.cached_clip_chain_index = Some((*id, index));
|
||||
index
|
||||
}
|
||||
|
||||
pub fn initialize_for_pipeline(&mut self, pipeline: &ScenePipeline) {
|
||||
debug_assert!(!self.pipeline_offsets.contains_key(&pipeline.pipeline_id));
|
||||
self.pipeline_offsets.insert(
|
||||
pipeline.pipeline_id,
|
||||
PipelineOffset {
|
||||
pipeline: pipeline.pipeline_id,
|
||||
spatial_offset: self.next_available_spatial_offset,
|
||||
clip_offset: self.next_available_clip_offset,
|
||||
}
|
||||
);
|
||||
|
||||
self.next_available_clip_offset += pipeline.display_list.total_clip_nodes();
|
||||
self.next_available_spatial_offset += pipeline.display_list.total_spatial_nodes();
|
||||
}
|
||||
|
||||
pub fn get_pipeline_offet<'a>(&'a mut self, id: PipelineId) -> &'a PipelineOffset {
|
||||
match self.cached_pipeline_offset {
|
||||
Some(ref offset) if offset.pipeline == id => offset,
|
||||
_ => {
|
||||
let offset = &self.pipeline_offsets[&id];
|
||||
self.cached_pipeline_offset = Some(*offset);
|
||||
offset
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_clip_node_index(&mut self, id: ClipId) -> ClipNodeIndex {
|
||||
pub fn get_clip_node_index(&self, id: ClipId) -> ClipNodeIndex {
|
||||
match id {
|
||||
ClipId::Clip(index, pipeline_id) => {
|
||||
let pipeline_offset = self.get_pipeline_offet(pipeline_id);
|
||||
ClipNodeIndex(pipeline_offset.clip_offset + index)
|
||||
ClipId::Clip(..) => {
|
||||
self.clip_node_map[&id]
|
||||
}
|
||||
ClipId::Spatial(..) => {
|
||||
// We could theoretically map back to the containing clip node with the current
|
||||
@ -154,6 +93,16 @@ impl ClipIdToIndexMapper {
|
||||
ClipId::ClipChain(_) => panic!("Tried to use ClipChain as scroll node."),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_spatial_node_index(&self, id: ClipId) -> SpatialNodeIndex {
|
||||
match id {
|
||||
ClipId::Clip(..) |
|
||||
ClipId::Spatial(..) => {
|
||||
self.spatial_node_map[&id]
|
||||
}
|
||||
ClipId::ClipChain(_) => panic!("Tried to use ClipChain as scroll node."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A structure that converts a serialized display list into a form that WebRender
|
||||
@ -248,7 +197,6 @@ impl<'a> DisplayListFlattener<'a> {
|
||||
clip_store: old_builder.clip_store.recycle(),
|
||||
};
|
||||
|
||||
flattener.id_to_index_mapper.initialize_for_pipeline(root_pipeline);
|
||||
flattener.push_root(
|
||||
root_pipeline_id,
|
||||
&root_pipeline.viewport_size,
|
||||
@ -401,13 +349,12 @@ impl<'a> DisplayListFlattener<'a> {
|
||||
info.previously_applied_offset,
|
||||
);
|
||||
|
||||
let index = self.get_spatial_node_index_for_clip_id(info.id);
|
||||
self.clip_scroll_tree.add_sticky_frame(
|
||||
index,
|
||||
let index = self.clip_scroll_tree.add_sticky_frame(
|
||||
clip_and_scroll.spatial_node_index, /* parent id */
|
||||
sticky_frame_info,
|
||||
info.id.pipeline_id(),
|
||||
);
|
||||
self.id_to_index_mapper.map_spatial_node(info.id, index);
|
||||
self.id_to_index_mapper.map_to_parent_clip_chain(info.id, parent_id);
|
||||
}
|
||||
|
||||
@ -532,8 +479,6 @@ impl<'a> DisplayListFlattener<'a> {
|
||||
},
|
||||
};
|
||||
|
||||
self.id_to_index_mapper.initialize_for_pipeline(pipeline);
|
||||
|
||||
//TODO: use or assert on `clip_and_scroll_ids.clip_node_id` ?
|
||||
let clip_chain_index = self.add_clip_node(
|
||||
info.clip_id,
|
||||
@ -791,23 +736,29 @@ impl<'a> DisplayListFlattener<'a> {
|
||||
None
|
||||
}
|
||||
|
||||
fn add_clip_sources(
|
||||
&mut self,
|
||||
clip_sources: Vec<ClipSource>,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
) -> Option<ClipSourcesIndex> {
|
||||
if clip_sources.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(self.clip_store.insert(ClipSources::new(clip_sources, spatial_node_index)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a primitive and add it to the prim store. This method doesn't
|
||||
/// add the primitive to the draw list, so can be used for creating
|
||||
/// sub-primitives.
|
||||
pub fn create_primitive(
|
||||
&mut self,
|
||||
info: &LayoutPrimitiveInfo,
|
||||
clip_sources: Vec<ClipSource>,
|
||||
clip_sources: Option<ClipSourcesIndex>,
|
||||
container: PrimitiveContainer,
|
||||
) -> PrimitiveIndex {
|
||||
let stacking_context = self.sc_stack.last().expect("bug: no stacking context!");
|
||||
|
||||
let clip_sources = if clip_sources.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(self.clip_store.insert(ClipSources::new(clip_sources)))
|
||||
};
|
||||
|
||||
self.prim_store.add_primitive(
|
||||
&info.rect,
|
||||
&info.clip_rect,
|
||||
@ -877,6 +828,10 @@ impl<'a> DisplayListFlattener<'a> {
|
||||
.iter()
|
||||
.map(|cs| cs.offset(&shadow.offset))
|
||||
.collect();
|
||||
let clip_sources = self.add_clip_sources(
|
||||
clip_sources,
|
||||
clip_and_scroll.spatial_node_index,
|
||||
);
|
||||
|
||||
// Construct and add a primitive for the given shadow.
|
||||
let shadow_prim_index = self.create_primitive(
|
||||
@ -893,6 +848,10 @@ impl<'a> DisplayListFlattener<'a> {
|
||||
}
|
||||
|
||||
if container.is_visible() {
|
||||
let clip_sources = self.add_clip_sources(
|
||||
clip_sources,
|
||||
clip_and_scroll.spatial_node_index,
|
||||
);
|
||||
let prim_index = self.create_primitive(info, clip_sources, container);
|
||||
if cfg!(debug_assertions) && ChasePrimitive::LocalRect(info.rect) == self.config.chase_primitive {
|
||||
println!("Chasing {:?}", prim_index);
|
||||
@ -919,7 +878,7 @@ impl<'a> DisplayListFlattener<'a> {
|
||||
None => ClipChainIndex::NO_CLIP,
|
||||
};
|
||||
let clip_and_scroll = ScrollNodeAndClipChain::new(
|
||||
self.get_spatial_node_index_for_clip_id(spatial_node),
|
||||
self.id_to_index_mapper.get_spatial_node_index(spatial_node),
|
||||
clip_chain_id
|
||||
);
|
||||
|
||||
@ -1219,10 +1178,8 @@ impl<'a> DisplayListFlattener<'a> {
|
||||
source_perspective: Option<LayoutTransform>,
|
||||
origin_in_parent_reference_frame: LayoutVector2D,
|
||||
) -> SpatialNodeIndex {
|
||||
let index = self.get_spatial_node_index_for_clip_id(reference_frame_id);
|
||||
let parent_index = parent_id.map(|id| self.get_spatial_node_index_for_clip_id(id));
|
||||
self.clip_scroll_tree.add_reference_frame(
|
||||
index,
|
||||
let parent_index = parent_id.map(|id| self.id_to_index_mapper.get_spatial_node_index(id));
|
||||
let index = self.clip_scroll_tree.add_reference_frame(
|
||||
parent_index,
|
||||
source_transform,
|
||||
source_perspective,
|
||||
@ -1230,6 +1187,7 @@ impl<'a> DisplayListFlattener<'a> {
|
||||
pipeline_id,
|
||||
);
|
||||
self.reference_frame_stack.push((reference_frame_id, index));
|
||||
self.id_to_index_mapper.map_spatial_node(reference_frame_id, index);
|
||||
|
||||
match parent_id {
|
||||
Some(ref parent_id) =>
|
||||
@ -1289,19 +1247,18 @@ impl<'a> DisplayListFlattener<'a> {
|
||||
parent_id: ClipId,
|
||||
clip_region: ClipRegion,
|
||||
) -> ClipChainIndex {
|
||||
let clip_sources = ClipSources::from(clip_region);
|
||||
let parent_clip_chain_index = self.id_to_index_mapper.get_clip_chain_index(&parent_id);
|
||||
let spatial_node = self.id_to_index_mapper.get_spatial_node_index(parent_id);
|
||||
|
||||
let clip_sources = ClipSources::from_region(clip_region, spatial_node);
|
||||
let handle = self.clip_store.insert(clip_sources);
|
||||
|
||||
let node_index = self.id_to_index_mapper.get_clip_node_index(new_node_id);
|
||||
let parent_clip_chain_index =
|
||||
self.id_to_index_mapper.get_clip_chain_index_and_cache_result(&parent_id);
|
||||
let spatial_node = self.get_spatial_node_index_for_clip_id(parent_id);
|
||||
let clip_chain_index = self.clip_scroll_tree.add_clip_node(
|
||||
node_index,
|
||||
let (node_index, clip_chain_index) = self.clip_scroll_tree.add_clip_node(
|
||||
parent_clip_chain_index,
|
||||
spatial_node,
|
||||
handle,
|
||||
);
|
||||
self.id_to_index_mapper.map_spatial_node(new_node_id, spatial_node);
|
||||
self.id_to_index_mapper.map_clip_node(new_node_id, node_index);
|
||||
self.id_to_index_mapper.add_clip_chain(new_node_id, clip_chain_index);
|
||||
clip_chain_index
|
||||
}
|
||||
@ -1316,10 +1273,8 @@ impl<'a> DisplayListFlattener<'a> {
|
||||
content_size: &LayoutSize,
|
||||
scroll_sensitivity: ScrollSensitivity,
|
||||
) -> SpatialNodeIndex {
|
||||
let node_index = self.get_spatial_node_index_for_clip_id(new_node_id);
|
||||
let parent_node_index = self.get_spatial_node_index_for_clip_id(parent_id);
|
||||
self.clip_scroll_tree.add_scroll_frame(
|
||||
node_index,
|
||||
let parent_node_index = self.id_to_index_mapper.get_spatial_node_index(parent_id);
|
||||
let node_index = self.clip_scroll_tree.add_scroll_frame(
|
||||
parent_node_index,
|
||||
external_id,
|
||||
pipeline_id,
|
||||
@ -1327,6 +1282,7 @@ impl<'a> DisplayListFlattener<'a> {
|
||||
content_size,
|
||||
scroll_sensitivity,
|
||||
);
|
||||
self.id_to_index_mapper.map_spatial_node(new_node_id, node_index);
|
||||
self.id_to_index_mapper.map_to_parent_clip_chain(new_node_id, &parent_id);
|
||||
node_index
|
||||
}
|
||||
@ -1455,7 +1411,7 @@ impl<'a> DisplayListFlattener<'a> {
|
||||
|
||||
let prim_index = self.create_primitive(
|
||||
info,
|
||||
Vec::new(),
|
||||
None,
|
||||
PrimitiveContainer::Brush(prim),
|
||||
);
|
||||
|
||||
@ -1967,28 +1923,14 @@ impl<'a> DisplayListFlattener<'a> {
|
||||
|
||||
pub fn map_clip_and_scroll(&mut self, info: &ClipAndScrollInfo) -> ScrollNodeAndClipChain {
|
||||
ScrollNodeAndClipChain::new(
|
||||
self.get_spatial_node_index_for_clip_id(info.scroll_node_id),
|
||||
self.id_to_index_mapper.get_clip_chain_index_and_cache_result(&info.clip_node_id())
|
||||
self.id_to_index_mapper.get_spatial_node_index(info.scroll_node_id),
|
||||
self.id_to_index_mapper.get_clip_chain_index(&info.clip_node_id())
|
||||
)
|
||||
}
|
||||
|
||||
pub fn simple_scroll_and_clip_chain(&mut self, id: &ClipId) -> ScrollNodeAndClipChain {
|
||||
self.map_clip_and_scroll(&ClipAndScrollInfo::simple(*id))
|
||||
}
|
||||
|
||||
pub fn get_spatial_node_index_for_clip_id(&mut self, id: ClipId,) -> SpatialNodeIndex {
|
||||
match id {
|
||||
ClipId::Spatial(index, pipeline_id) => {
|
||||
let pipeline_offset = self.id_to_index_mapper.get_pipeline_offet(pipeline_id);
|
||||
SpatialNodeIndex(pipeline_offset.spatial_offset + index)
|
||||
}
|
||||
ClipId::Clip(..) => {
|
||||
let clip_node_index = self.id_to_index_mapper.get_clip_node_index(id);
|
||||
self.clip_scroll_tree.clip_nodes[clip_node_index.0].spatial_node
|
||||
}
|
||||
ClipId::ClipChain(_) => panic!("Tried to use ClipChain as scroll node."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_scene(config: &FrameBuilderConfig, request: SceneRequest) -> BuiltScene {
|
||||
|
@ -3,7 +3,6 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use util::recycle_vec;
|
||||
|
||||
// TODO(gw): Add an occupied list head, for fast
|
||||
// iteration of the occupied list to implement
|
||||
@ -86,15 +85,6 @@ impl<T, M> FreeList<T, M> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn recycle(self) -> FreeList<T, M> {
|
||||
FreeList {
|
||||
slots: recycle_vec(self.slots),
|
||||
free_list_head: None,
|
||||
active_count: 0,
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.slots.clear();
|
||||
self.free_list_head = None;
|
||||
|
@ -195,6 +195,7 @@ impl PrimitiveHeaders {
|
||||
|
||||
// This is a convenience type used to make it easier to pass
|
||||
// the common parts around during batching.
|
||||
#[derive(Debug)]
|
||||
pub struct PrimitiveHeader {
|
||||
pub local_rect: LayoutRect,
|
||||
pub local_clip_rect: LayoutRect,
|
||||
@ -349,12 +350,15 @@ impl From<BrushInstance> for PrimitiveInstance {
|
||||
pub struct TransformPaletteId(pub u32);
|
||||
|
||||
impl TransformPaletteId {
|
||||
// Get the palette ID for an identity transform.
|
||||
pub fn identity() -> TransformPaletteId {
|
||||
TransformPaletteId(0)
|
||||
/// Identity transform ID.
|
||||
pub const IDENTITY: Self = TransformPaletteId(0);
|
||||
|
||||
/// Extract the spatial node index from the id.
|
||||
pub fn _spatial_node_index(&self) -> SpatialNodeIndex {
|
||||
SpatialNodeIndex(self.0 as usize & 0xFFFFFF)
|
||||
}
|
||||
|
||||
// Extract the transform kind from the id.
|
||||
/// Extract the transform kind from the id.
|
||||
pub fn transform_kind(&self) -> TransformedRectKind {
|
||||
if (self.0 >> 24) == 0 {
|
||||
TransformedRectKind::AxisAligned
|
||||
|
@ -34,6 +34,29 @@ pub struct HitTestClipNode {
|
||||
regions: Vec<HitTestRegion>,
|
||||
}
|
||||
|
||||
impl HitTestClipNode {
|
||||
fn new(node: &ClipNode, clip_store: &ClipStore) -> Self {
|
||||
let clips = clip_store.get(node.clip_sources_index);
|
||||
let regions = clips.clips().iter().map(|source| {
|
||||
match source.0 {
|
||||
ClipSource::Rectangle(ref rect, mode) => HitTestRegion::Rectangle(*rect, mode),
|
||||
ClipSource::RoundedRectangle(ref rect, ref radii, ref mode) =>
|
||||
HitTestRegion::RoundedRectangle(*rect, *radii, *mode),
|
||||
ClipSource::Image(ref mask) => HitTestRegion::Rectangle(mask.rect, ClipMode::Clip),
|
||||
ClipSource::LineDecoration(_) |
|
||||
ClipSource::BoxShadow(_) => {
|
||||
unreachable!("Didn't expect to hit test against BorderCorner / BoxShadow / LineDecoration");
|
||||
}
|
||||
}
|
||||
}).collect();
|
||||
|
||||
HitTestClipNode {
|
||||
spatial_node: clips.spatial_node_index,
|
||||
regions,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A description of a clip chain in the HitTester. This is used to describe
|
||||
/// hierarchical clip scroll nodes as well as ClipChains, so that they can be
|
||||
/// handled the same way during hit testing. Once we represent all ClipChains
|
||||
@ -148,15 +171,11 @@ impl HitTester {
|
||||
}
|
||||
|
||||
for (index, node) in clip_scroll_tree.clip_nodes.iter().enumerate() {
|
||||
self.clip_nodes.push(HitTestClipNode {
|
||||
spatial_node: node.spatial_node,
|
||||
regions: get_regions_for_clip_node(node, clip_store),
|
||||
});
|
||||
|
||||
let clip_chain = self.clip_chains.get_mut(node.clip_chain_index.0).unwrap();
|
||||
clip_chain.parent =
|
||||
clip_scroll_tree.get_clip_chain(node.clip_chain_index).parent_index;
|
||||
clip_chain.clips = vec![ClipNodeIndex(index)];
|
||||
self.clip_nodes.push(HitTestClipNode::new(node, clip_store));
|
||||
let clip_chain = self.clip_chains.get_mut(node.clip_chain_index.0).unwrap();
|
||||
clip_chain.parent =
|
||||
clip_scroll_tree.get_clip_chain(node.clip_chain_index).parent_index;
|
||||
clip_chain.clips = vec![ClipNodeIndex(index)];
|
||||
}
|
||||
|
||||
for descriptor in &clip_scroll_tree.clip_chains_descriptors {
|
||||
@ -346,33 +365,6 @@ impl HitTester {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_regions_for_clip_node(
|
||||
node: &ClipNode,
|
||||
clip_store: &ClipStore
|
||||
) -> Vec<HitTestRegion> {
|
||||
let handle = match node.handle.as_ref() {
|
||||
Some(handle) => handle,
|
||||
None => {
|
||||
warn!("Encountered an empty clip node unexpectedly.");
|
||||
return Vec::new()
|
||||
}
|
||||
};
|
||||
|
||||
let clips = clip_store.get(handle).clips();
|
||||
clips.iter().map(|source| {
|
||||
match source.0 {
|
||||
ClipSource::Rectangle(ref rect, mode) => HitTestRegion::Rectangle(*rect, mode),
|
||||
ClipSource::RoundedRectangle(ref rect, ref radii, ref mode) =>
|
||||
HitTestRegion::RoundedRectangle(*rect, *radii, *mode),
|
||||
ClipSource::Image(ref mask) => HitTestRegion::Rectangle(mask.rect, ClipMode::Clip),
|
||||
ClipSource::LineDecoration(_) |
|
||||
ClipSource::BoxShadow(_) => {
|
||||
unreachable!("Didn't expect to hit test against BorderCorner / BoxShadow / LineDecoration");
|
||||
}
|
||||
}
|
||||
}).collect()
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
enum ClippedIn {
|
||||
ClippedIn,
|
||||
|
@ -13,7 +13,7 @@ use border::{BorderCacheKey, BorderRenderTaskInfo};
|
||||
use box_shadow::BLUR_SAMPLE_SCALE;
|
||||
use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId, SpatialNodeIndex};
|
||||
use clip::{ClipChain, ClipChainNode, ClipChainNodeIter, ClipChainNodeRef, ClipSource};
|
||||
use clip::{ClipSourcesHandle, ClipWorkItem};
|
||||
use clip::{ClipSourcesIndex, ClipWorkItem};
|
||||
use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureContext, PictureState};
|
||||
use frame_builder::PrimitiveRunContext;
|
||||
use glyph_rasterizer::{FontInstance, FontTransform, GlyphKey, FONT_SIZE_LIMIT};
|
||||
@ -188,7 +188,7 @@ pub struct ScreenRect {
|
||||
#[derive(Debug)]
|
||||
pub struct PrimitiveMetadata {
|
||||
pub opacity: PrimitiveOpacity,
|
||||
pub clip_sources: Option<ClipSourcesHandle>,
|
||||
pub clip_sources_index: Option<ClipSourcesIndex>,
|
||||
pub prim_kind: PrimitiveKind,
|
||||
pub cpu_prim_index: SpecificPrimitiveIndex,
|
||||
pub gpu_location: GpuCacheHandle,
|
||||
@ -1281,14 +1281,14 @@ impl PrimitiveStore {
|
||||
local_rect: &LayoutRect,
|
||||
local_clip_rect: &LayoutRect,
|
||||
is_backface_visible: bool,
|
||||
clip_sources: Option<ClipSourcesHandle>,
|
||||
clip_sources_index: Option<ClipSourcesIndex>,
|
||||
tag: Option<ItemTag>,
|
||||
container: PrimitiveContainer,
|
||||
) -> PrimitiveIndex {
|
||||
let prim_index = self.cpu_metadata.len();
|
||||
|
||||
let base_metadata = PrimitiveMetadata {
|
||||
clip_sources,
|
||||
clip_sources_index,
|
||||
gpu_location: GpuCacheHandle::new(),
|
||||
clip_task_id: None,
|
||||
local_rect: *local_rect,
|
||||
@ -1983,6 +1983,9 @@ impl PrimitiveStore {
|
||||
match brush.segment_desc {
|
||||
Some(ref segment_desc) => {
|
||||
for segment in &segment_desc.segments {
|
||||
if cfg!(debug_assertions) && self.chase_id == Some(prim_index) {
|
||||
println!("\t\t{:?}", segment);
|
||||
}
|
||||
// has to match VECS_PER_SEGMENT
|
||||
request.write_segment(
|
||||
segment.local_rect,
|
||||
@ -2059,7 +2062,7 @@ impl PrimitiveStore {
|
||||
continue;
|
||||
}
|
||||
|
||||
let local_clips = frame_state.clip_store.get_opt(&clip_item.clip_sources).expect("bug");
|
||||
let local_clips = frame_state.clip_store.get(clip_item.clip_sources_index);
|
||||
rect_clips_only = rect_clips_only && local_clips.only_rectangular_clips;
|
||||
|
||||
// TODO(gw): We can easily extend the segment builder to support these clip sources in
|
||||
@ -2074,7 +2077,7 @@ impl PrimitiveStore {
|
||||
// of doing that, only segment with clips that have the same positioning node.
|
||||
// TODO(mrobinson, #2858): It may make sense to include these nodes, resegmenting only
|
||||
// when necessary while scrolling.
|
||||
if clip_item.spatial_node_index != prim_run_context.spatial_node_index {
|
||||
if local_clips.spatial_node_index != prim_run_context.spatial_node_index {
|
||||
// We don't need to generate a global clip mask for rectangle clips because we are
|
||||
// in the same coordinate system and rectangular clips are handled by the local
|
||||
// clip chain rectangle.
|
||||
@ -2285,8 +2288,8 @@ impl PrimitiveStore {
|
||||
let transform = &prim_run_context.scroll_node.world_content_transform;
|
||||
let extra_clip = {
|
||||
let metadata = &self.cpu_metadata[prim_index.0];
|
||||
metadata.clip_sources.as_ref().map(|clip_sources| {
|
||||
let prim_clips = frame_state.clip_store.get_mut(clip_sources);
|
||||
metadata.clip_sources_index.map(|clip_sources_index| {
|
||||
let prim_clips = frame_state.clip_store.get_mut(clip_sources_index);
|
||||
prim_clips.update(
|
||||
frame_state.gpu_cache,
|
||||
frame_state.resource_cache,
|
||||
@ -2307,8 +2310,7 @@ impl PrimitiveStore {
|
||||
|
||||
Arc::new(ClipChainNode {
|
||||
work_item: ClipWorkItem {
|
||||
spatial_node_index: prim_run_context.spatial_node_index,
|
||||
clip_sources: clip_sources.weak(),
|
||||
clip_sources_index,
|
||||
coordinate_system_id: prim_coordinate_system_id,
|
||||
},
|
||||
// The local_clip_rect a property of ClipChain nodes that are ClipNodes.
|
||||
@ -2643,10 +2645,6 @@ impl PrimitiveStore {
|
||||
};
|
||||
|
||||
for run in &pic_context.prim_runs {
|
||||
if run.is_chasing(self.chase_id) {
|
||||
println!("\tpreparing a run of length {} in pipeline {:?}",
|
||||
run.count, pic_context.pipeline_id);
|
||||
}
|
||||
// TODO(gw): Perhaps we can restructure this to not need to create
|
||||
// a new primitive context for every run (if the hash
|
||||
// lookups ever show up in a profile).
|
||||
@ -2656,6 +2654,13 @@ impl PrimitiveStore {
|
||||
let clip_chain = &frame_context
|
||||
.clip_chains[run.clip_and_scroll.clip_chain_index.0];
|
||||
|
||||
if run.is_chasing(self.chase_id) {
|
||||
println!("\tpreparing a run of length {} in pipeline {:?}",
|
||||
run.count, pic_context.pipeline_id);
|
||||
println!("\trun {:?}", run.clip_and_scroll);
|
||||
println!("\ttransform {:?}", scroll_node.world_content_transform.to_transform());
|
||||
}
|
||||
|
||||
// Mark whether this picture contains any complex coordinate
|
||||
// systems, due to either the scroll node or the clip-chain.
|
||||
pic_state.has_non_root_coord_system |=
|
||||
@ -2716,7 +2721,12 @@ impl PrimitiveStore {
|
||||
};
|
||||
|
||||
let local_clip_chain_rect = match clip_chain_rect {
|
||||
Some(rect) if rect.is_empty() => continue,
|
||||
Some(rect) if rect.is_empty() => {
|
||||
if run.is_chasing(self.chase_id) {
|
||||
println!("\tculled by empty chain rect");
|
||||
}
|
||||
continue
|
||||
},
|
||||
Some(rect) => rect,
|
||||
None => frame_context.max_local_clip,
|
||||
};
|
||||
@ -2749,7 +2759,12 @@ impl PrimitiveStore {
|
||||
let clipped_rect = match clip_chain_rect {
|
||||
Some(ref chain_rect) => match prim_local_rect.intersection(chain_rect) {
|
||||
Some(rect) => rect,
|
||||
None => continue,
|
||||
None => {
|
||||
if cfg!(debug_assertions) && self.chase_id == Some(prim_index) {
|
||||
println!("\tculled by chain rect {:?}", chain_rect);
|
||||
}
|
||||
continue
|
||||
},
|
||||
},
|
||||
None => prim_local_rect,
|
||||
};
|
||||
|
@ -169,6 +169,97 @@ impl Document {
|
||||
!self.view.window_size.is_empty_or_negative()
|
||||
}
|
||||
|
||||
fn process_frame_msg(
|
||||
&mut self,
|
||||
message: FrameMsg,
|
||||
) -> DocumentOps {
|
||||
match message {
|
||||
FrameMsg::UpdateEpoch(pipeline_id, epoch) => {
|
||||
self.current.scene.update_epoch(pipeline_id, epoch);
|
||||
|
||||
DocumentOps::nop()
|
||||
}
|
||||
FrameMsg::EnableFrameOutput(pipeline_id, enable) => {
|
||||
if enable {
|
||||
self.output_pipelines.insert(pipeline_id);
|
||||
} else {
|
||||
self.output_pipelines.remove(&pipeline_id);
|
||||
}
|
||||
DocumentOps::nop()
|
||||
}
|
||||
FrameMsg::Scroll(delta, cursor) => {
|
||||
profile_scope!("Scroll");
|
||||
|
||||
let mut should_render = true;
|
||||
let node_index = match self.hit_tester {
|
||||
Some(ref hit_tester) => {
|
||||
// Ideally we would call self.scroll_nearest_scrolling_ancestor here, but
|
||||
// we need have to avoid a double-borrow.
|
||||
let test = HitTest::new(None, cursor, HitTestFlags::empty());
|
||||
hit_tester.find_node_under_point(test)
|
||||
}
|
||||
None => {
|
||||
should_render = false;
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let should_render =
|
||||
should_render &&
|
||||
self.scroll_nearest_scrolling_ancestor(delta, node_index) &&
|
||||
self.render_on_scroll == Some(true);
|
||||
DocumentOps {
|
||||
scroll: true,
|
||||
render: should_render,
|
||||
composite: should_render,
|
||||
..DocumentOps::nop()
|
||||
}
|
||||
}
|
||||
FrameMsg::HitTest(pipeline_id, point, flags, tx) => {
|
||||
|
||||
let result = match self.hit_tester {
|
||||
Some(ref hit_tester) => {
|
||||
hit_tester.hit_test(HitTest::new(pipeline_id, point, flags))
|
||||
}
|
||||
None => HitTestResult { items: Vec::new() },
|
||||
};
|
||||
|
||||
tx.send(result).unwrap();
|
||||
DocumentOps::nop()
|
||||
}
|
||||
FrameMsg::SetPan(pan) => {
|
||||
self.view.pan = pan;
|
||||
DocumentOps::nop()
|
||||
}
|
||||
FrameMsg::ScrollNodeWithId(origin, id, clamp) => {
|
||||
profile_scope!("ScrollNodeWithScrollId");
|
||||
|
||||
let should_render = self.scroll_node(origin, id, clamp)
|
||||
&& self.render_on_scroll == Some(true);
|
||||
|
||||
DocumentOps {
|
||||
scroll: true,
|
||||
render: should_render,
|
||||
composite: should_render,
|
||||
..DocumentOps::nop()
|
||||
}
|
||||
}
|
||||
FrameMsg::GetScrollNodeState(tx) => {
|
||||
profile_scope!("GetScrollNodeState");
|
||||
tx.send(self.get_scroll_node_state()).unwrap();
|
||||
DocumentOps::nop()
|
||||
}
|
||||
FrameMsg::UpdateDynamicProperties(property_bindings) => {
|
||||
self.dynamic_properties.set_properties(property_bindings);
|
||||
DocumentOps::nop()
|
||||
}
|
||||
FrameMsg::AppendDynamicProperties(property_bindings) => {
|
||||
self.dynamic_properties.add_properties(property_bindings);
|
||||
DocumentOps::nop()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: We will probably get rid of this soon and always forward to the scene building thread.
|
||||
fn build_scene(&mut self, resource_cache: &mut ResourceCache, scene_id: u64) {
|
||||
let max_texture_size = resource_cache.max_texture_size();
|
||||
@ -601,100 +692,6 @@ impl RenderBackend {
|
||||
}
|
||||
}
|
||||
|
||||
fn process_frame_msg(
|
||||
&mut self,
|
||||
document_id: DocumentId,
|
||||
message: FrameMsg,
|
||||
) -> DocumentOps {
|
||||
let doc = self.documents.get_mut(&document_id).expect("No document?");
|
||||
|
||||
match message {
|
||||
FrameMsg::UpdateEpoch(pipeline_id, epoch) => {
|
||||
doc.current.scene.update_epoch(pipeline_id, epoch);
|
||||
|
||||
DocumentOps::nop()
|
||||
}
|
||||
FrameMsg::EnableFrameOutput(pipeline_id, enable) => {
|
||||
if enable {
|
||||
doc.output_pipelines.insert(pipeline_id);
|
||||
} else {
|
||||
doc.output_pipelines.remove(&pipeline_id);
|
||||
}
|
||||
DocumentOps::nop()
|
||||
}
|
||||
FrameMsg::Scroll(delta, cursor) => {
|
||||
profile_scope!("Scroll");
|
||||
|
||||
let mut should_render = true;
|
||||
let node_index = match doc.hit_tester {
|
||||
Some(ref hit_tester) => {
|
||||
// Ideally we would call doc.scroll_nearest_scrolling_ancestor here, but
|
||||
// we need have to avoid a double-borrow.
|
||||
let test = HitTest::new(None, cursor, HitTestFlags::empty());
|
||||
hit_tester.find_node_under_point(test)
|
||||
}
|
||||
None => {
|
||||
should_render = false;
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let should_render =
|
||||
should_render &&
|
||||
doc.scroll_nearest_scrolling_ancestor(delta, node_index) &&
|
||||
doc.render_on_scroll == Some(true);
|
||||
DocumentOps {
|
||||
scroll: true,
|
||||
render: should_render,
|
||||
composite: should_render,
|
||||
..DocumentOps::nop()
|
||||
}
|
||||
}
|
||||
FrameMsg::HitTest(pipeline_id, point, flags, tx) => {
|
||||
|
||||
let result = match doc.hit_tester {
|
||||
Some(ref hit_tester) => {
|
||||
hit_tester.hit_test(HitTest::new(pipeline_id, point, flags))
|
||||
}
|
||||
None => HitTestResult { items: Vec::new() },
|
||||
};
|
||||
|
||||
tx.send(result).unwrap();
|
||||
DocumentOps::nop()
|
||||
}
|
||||
FrameMsg::SetPan(pan) => {
|
||||
doc.view.pan = pan;
|
||||
DocumentOps::nop()
|
||||
}
|
||||
FrameMsg::ScrollNodeWithId(origin, id, clamp) => {
|
||||
profile_scope!("ScrollNodeWithScrollId");
|
||||
|
||||
let should_render = doc.scroll_node(origin, id, clamp)
|
||||
&& doc.render_on_scroll == Some(true);
|
||||
|
||||
DocumentOps {
|
||||
scroll: true,
|
||||
render: should_render,
|
||||
composite: should_render,
|
||||
..DocumentOps::nop()
|
||||
}
|
||||
}
|
||||
FrameMsg::GetScrollNodeState(tx) => {
|
||||
profile_scope!("GetScrollNodeState");
|
||||
tx.send(doc.get_scroll_node_state()).unwrap();
|
||||
DocumentOps::nop()
|
||||
}
|
||||
FrameMsg::UpdateDynamicProperties(property_bindings) => {
|
||||
doc.dynamic_properties.set_properties(property_bindings);
|
||||
DocumentOps::render()
|
||||
}
|
||||
FrameMsg::AppendDynamicProperties(property_bindings) => {
|
||||
doc.dynamic_properties.add_properties(property_bindings);
|
||||
DocumentOps::render()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn next_namespace_id(&self) -> IdNamespace {
|
||||
IdNamespace(NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed) as u32)
|
||||
}
|
||||
@ -1070,12 +1067,16 @@ impl RenderBackend {
|
||||
}
|
||||
}
|
||||
|
||||
let doc = self.documents.get_mut(&document_id).unwrap();
|
||||
|
||||
for frame_msg in transaction_msg.frame_ops {
|
||||
let _timer = profile_counters.total_time.timer();
|
||||
op.combine(self.process_frame_msg(document_id, frame_msg));
|
||||
op.combine(doc.process_frame_msg(frame_msg));
|
||||
}
|
||||
|
||||
let doc = self.documents.get_mut(&document_id).unwrap();
|
||||
if doc.dynamic_properties.flush_pending_updates() {
|
||||
op.render = true;
|
||||
}
|
||||
|
||||
if transaction_msg.generate_frame {
|
||||
if let Some(ref mut ros) = doc.render_on_scroll {
|
||||
|
@ -403,7 +403,7 @@ impl RenderTask {
|
||||
// whether a ClipSources contains any box-shadows and skip
|
||||
// this iteration for the majority of cases.
|
||||
for clip_item in &clips {
|
||||
let clip_sources = clip_store.get_opt_mut(&clip_item.clip_sources).expect("bug");
|
||||
let clip_sources = clip_store.get_mut(clip_item.clip_sources_index);
|
||||
for &mut (ref mut clip, _) in &mut clip_sources.clips {
|
||||
match *clip {
|
||||
ClipSource::BoxShadow(ref mut info) => {
|
||||
|
@ -1235,26 +1235,10 @@ impl ResourceCache {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_cached_image(
|
||||
&self,
|
||||
request: ImageRequest,
|
||||
) -> Result<CacheItem, ()> {
|
||||
pub fn get_cached_image(&self, request: ImageRequest) -> Result<CacheItem, ()> {
|
||||
debug_assert_eq!(self.state, State::QueryResources);
|
||||
|
||||
// TODO(Jerry): add a debug option to visualize the corresponding area for
|
||||
// the Err() case of CacheItem.
|
||||
match *self.cached_images.get(&request.key) {
|
||||
ImageResult::UntiledAuto(ref image_info) => {
|
||||
Ok(self.texture_cache.get(&image_info.texture_cache_handle))
|
||||
}
|
||||
ImageResult::Multi(ref entries) => {
|
||||
let image_info = entries.get(&request.into());
|
||||
Ok(self.texture_cache.get(&image_info.texture_cache_handle))
|
||||
}
|
||||
ImageResult::Err(_) => {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
let image_info = self.get_image_info(request)?;
|
||||
Ok(self.get_texture_cache_item(&image_info.texture_cache_handle))
|
||||
}
|
||||
|
||||
pub fn get_cached_render_task(
|
||||
@ -1264,6 +1248,18 @@ impl ResourceCache {
|
||||
self.cached_render_tasks.get_cache_entry(handle)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_image_info(&self, request: ImageRequest) -> Result<&CachedImageInfo, ()> {
|
||||
// TODO(Jerry): add a debug option to visualize the corresponding area for
|
||||
// the Err() case of CacheItem.
|
||||
match *self.cached_images.get(&request.key) {
|
||||
ImageResult::UntiledAuto(ref image_info) => Ok(image_info),
|
||||
ImageResult::Multi(ref entries) => Ok(entries.get(&request.into())),
|
||||
ImageResult::Err(_) => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_texture_cache_item(&self, handle: &TextureCacheHandle) -> CacheItem {
|
||||
self.texture_cache.get(handle)
|
||||
}
|
||||
|
@ -13,10 +13,11 @@ use std::sync::Arc;
|
||||
/// re-submitting the display list itself.
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[derive(Clone)]
|
||||
pub struct SceneProperties {
|
||||
transform_properties: FastHashMap<PropertyBindingId, LayoutTransform>,
|
||||
float_properties: FastHashMap<PropertyBindingId, f32>,
|
||||
current_properties: DynamicProperties,
|
||||
pending_properties: Option<DynamicProperties>,
|
||||
}
|
||||
|
||||
impl SceneProperties {
|
||||
@ -24,27 +25,60 @@ impl SceneProperties {
|
||||
SceneProperties {
|
||||
transform_properties: FastHashMap::default(),
|
||||
float_properties: FastHashMap::default(),
|
||||
current_properties: DynamicProperties::default(),
|
||||
pending_properties: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the current property list for this display list.
|
||||
pub fn set_properties(&mut self, properties: DynamicProperties) {
|
||||
self.transform_properties.clear();
|
||||
self.float_properties.clear();
|
||||
self.add_properties(properties);
|
||||
self.pending_properties = Some(properties);
|
||||
}
|
||||
|
||||
/// Add to the current property list for this display list.
|
||||
pub fn add_properties(&mut self, properties: DynamicProperties) {
|
||||
for property in properties.transforms {
|
||||
self.transform_properties
|
||||
.insert(property.key.id, property.value);
|
||||
let mut pending_properties = self.pending_properties
|
||||
.take()
|
||||
.unwrap_or_default();
|
||||
|
||||
pending_properties.transforms.extend(properties.transforms);
|
||||
pending_properties.floats.extend(properties.floats);
|
||||
|
||||
self.pending_properties = Some(pending_properties);
|
||||
}
|
||||
|
||||
/// Flush any pending updates to the scene properties. Returns
|
||||
/// true if the properties have changed since the last flush
|
||||
/// was called. This code allows properties to be changed by
|
||||
/// multiple set_properties and add_properties calls during a
|
||||
/// single transaction, and still correctly determine if any
|
||||
/// properties have changed. This can have significant power
|
||||
/// saving implications, allowing a frame build to be skipped
|
||||
/// if the properties haven't changed in many cases.
|
||||
pub fn flush_pending_updates(&mut self) -> bool {
|
||||
let mut properties_changed = false;
|
||||
|
||||
if let Some(pending_properties) = self.pending_properties.take() {
|
||||
if pending_properties != self.current_properties {
|
||||
self.transform_properties.clear();
|
||||
self.float_properties.clear();
|
||||
|
||||
for property in &pending_properties.transforms {
|
||||
self.transform_properties
|
||||
.insert(property.key.id, property.value);
|
||||
}
|
||||
|
||||
for property in &pending_properties.floats {
|
||||
self.float_properties
|
||||
.insert(property.key.id, property.value);
|
||||
}
|
||||
|
||||
self.current_properties = pending_properties;
|
||||
properties_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
for property in properties.floats {
|
||||
self.float_properties
|
||||
.insert(property.key.id, property.value);
|
||||
}
|
||||
properties_changed
|
||||
}
|
||||
|
||||
/// Get the current value for a transform property.
|
||||
|
@ -26,11 +26,6 @@ pub enum SpatialNodeType {
|
||||
|
||||
/// A reference frame establishes a new coordinate space in the tree.
|
||||
ReferenceFrame(ReferenceFrameInfo),
|
||||
|
||||
/// An empty node, used to pad the ClipScrollTree's array of nodes so that
|
||||
/// we can immediately use each assigned SpatialNodeIndex. After display
|
||||
/// list flattening this node type should never be used.
|
||||
Empty,
|
||||
}
|
||||
|
||||
/// Contains information common among all types of ClipScrollTree nodes.
|
||||
@ -94,10 +89,6 @@ impl SpatialNode {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn empty() -> SpatialNode {
|
||||
Self::new(PipelineId::dummy(), None, SpatialNodeType::Empty)
|
||||
}
|
||||
|
||||
pub fn new_scroll_frame(
|
||||
pipeline_id: PipelineId,
|
||||
parent_index: SpatialNodeIndex,
|
||||
@ -494,7 +485,6 @@ impl SpatialNode {
|
||||
state.nearest_scrolling_ancestor_viewport
|
||||
.translate(&translation);
|
||||
}
|
||||
SpatialNodeType::Empty => unreachable!("Empty node remaining in ClipScrollTree."),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1090,7 +1090,7 @@ impl<T> From<T> for PropertyBinding<T> {
|
||||
|
||||
/// The current value of an animated property. This is
|
||||
/// supplied by the calling code.
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq)]
|
||||
pub struct PropertyValue<T> {
|
||||
pub key: PropertyBindingKey<T>,
|
||||
pub value: T,
|
||||
@ -1099,7 +1099,7 @@ pub struct PropertyValue<T> {
|
||||
/// When using `generate_frame()`, a list of `PropertyValue` structures
|
||||
/// can optionally be supplied to provide the current value of any
|
||||
/// animated properties.
|
||||
#[derive(Clone, Deserialize, Serialize, Debug)]
|
||||
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Default)]
|
||||
pub struct DynamicProperties {
|
||||
pub transforms: Vec<PropertyValue<LayoutTransform>>,
|
||||
pub floats: Vec<PropertyValue<f32>>,
|
||||
|
@ -1 +1 @@
|
||||
e850fbd2e0e60a8de76c2d2464f0fa27316d5949
|
||||
8a4fe66528aa362721e4048aac3cd5abf7faaf2c
|
||||
|
@ -182,23 +182,18 @@ impl WindowWrapper {
|
||||
}
|
||||
|
||||
fn get_inner_size(&self) -> DeviceUintSize {
|
||||
//HACK: `winit` needs to figure out its hidpi story...
|
||||
#[cfg(target_os = "macos")]
|
||||
fn inner_size(window: &winit::Window) -> LogicalSize {
|
||||
let LogicalSize { width, height } = window.get_inner_size().unwrap();
|
||||
let factor = window.get_hidpi_factor();
|
||||
LogicalSize::new(width * factor, height * factor)
|
||||
fn inner_size(window: &winit::Window) -> DeviceUintSize {
|
||||
let size = window
|
||||
.get_inner_size()
|
||||
.unwrap()
|
||||
.to_physical(window.get_hidpi_factor());
|
||||
DeviceUintSize::new(size.width as u32, size.height as u32)
|
||||
}
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
fn inner_size(window: &winit::Window) -> LogicalSize {
|
||||
window.get_inner_size().unwrap()
|
||||
}
|
||||
let LogicalSize { width, height } = match *self {
|
||||
match *self {
|
||||
WindowWrapper::Window(ref window, _) => inner_size(window.window()),
|
||||
WindowWrapper::Angle(ref window, ..) => inner_size(window),
|
||||
WindowWrapper::Headless(ref context, _) => LogicalSize::new(context.width as f64, context.height as f64),
|
||||
};
|
||||
DeviceUintSize::new(width as u32, height as u32)
|
||||
WindowWrapper::Headless(ref context, _) => DeviceUintSize::new(context.width, context.height),
|
||||
}
|
||||
}
|
||||
|
||||
fn hidpi_factor(&self) -> f32 {
|
||||
|
Loading…
Reference in New Issue
Block a user