mirror of
https://github.com/servo/servo.git
synced 2025-09-23 13:20:11 +01:00
layout: allow only repaint when css background and border image loaded (#39201)
This change allows that only new display list is built when css background and border image loaded. Testing: This change should not change any behaviors so covered by existing WPT tests. Signed-off-by: sharpshooter_pt <ibluegalaxy_taoj@163.com>
This commit is contained in:
parent
e00bfb525b
commit
30d3706a2b
5 changed files with 68 additions and 13 deletions
|
@ -10,7 +10,8 @@ use fnv::FnvHashMap;
|
||||||
use fonts::FontContext;
|
use fonts::FontContext;
|
||||||
use layout_api::wrapper_traits::ThreadSafeLayoutNode;
|
use layout_api::wrapper_traits::ThreadSafeLayoutNode;
|
||||||
use layout_api::{
|
use layout_api::{
|
||||||
IFrameSizes, ImageAnimationState, PendingImage, PendingImageState, PendingRasterizationImage,
|
IFrameSizes, ImageAnimationState, LayoutImageDestination, PendingImage, PendingImageState,
|
||||||
|
PendingRasterizationImage,
|
||||||
};
|
};
|
||||||
use net_traits::image_cache::{
|
use net_traits::image_cache::{
|
||||||
Image as CachedImage, ImageCache, ImageCacheResult, ImageOrMetadataAvailable, PendingImageId,
|
Image as CachedImage, ImageCache, ImageCacheResult, ImageOrMetadataAvailable, PendingImageId,
|
||||||
|
@ -128,6 +129,7 @@ impl ImageResolver {
|
||||||
node: OpaqueNode,
|
node: OpaqueNode,
|
||||||
url: ServoUrl,
|
url: ServoUrl,
|
||||||
use_placeholder: UsePlaceholder,
|
use_placeholder: UsePlaceholder,
|
||||||
|
destination: LayoutImageDestination,
|
||||||
) -> LayoutImageCacheResult {
|
) -> LayoutImageCacheResult {
|
||||||
// Check for available image or start tracking.
|
// Check for available image or start tracking.
|
||||||
let cache_result = self.image_cache.get_cached_image_status(
|
let cache_result = self.image_cache.get_cached_image_status(
|
||||||
|
@ -149,6 +151,7 @@ impl ImageResolver {
|
||||||
node: node.into(),
|
node: node.into(),
|
||||||
id,
|
id,
|
||||||
origin: self.origin.clone(),
|
origin: self.origin.clone(),
|
||||||
|
destination,
|
||||||
};
|
};
|
||||||
self.pending_images.lock().push(image);
|
self.pending_images.lock().push(image);
|
||||||
LayoutImageCacheResult::Pending
|
LayoutImageCacheResult::Pending
|
||||||
|
@ -160,6 +163,7 @@ impl ImageResolver {
|
||||||
node: node.into(),
|
node: node.into(),
|
||||||
id,
|
id,
|
||||||
origin: self.origin.clone(),
|
origin: self.origin.clone(),
|
||||||
|
destination,
|
||||||
};
|
};
|
||||||
self.pending_images.lock().push(image);
|
self.pending_images.lock().push(image);
|
||||||
LayoutImageCacheResult::Pending
|
LayoutImageCacheResult::Pending
|
||||||
|
@ -192,6 +196,7 @@ impl ImageResolver {
|
||||||
node: OpaqueNode,
|
node: OpaqueNode,
|
||||||
url: ServoUrl,
|
url: ServoUrl,
|
||||||
use_placeholder: UsePlaceholder,
|
use_placeholder: UsePlaceholder,
|
||||||
|
destination: LayoutImageDestination,
|
||||||
) -> Result<CachedImage, ResolveImageError> {
|
) -> Result<CachedImage, ResolveImageError> {
|
||||||
if let Some(cached_image) = self
|
if let Some(cached_image) = self
|
||||||
.resolved_images_cache
|
.resolved_images_cache
|
||||||
|
@ -201,7 +206,8 @@ impl ImageResolver {
|
||||||
return cached_image.clone();
|
return cached_image.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = self.get_or_request_image_or_meta(node, url.clone(), use_placeholder);
|
let result =
|
||||||
|
self.get_or_request_image_or_meta(node, url.clone(), use_placeholder, destination);
|
||||||
match result {
|
match result {
|
||||||
LayoutImageCacheResult::DataAvailable(img_or_meta) => match img_or_meta {
|
LayoutImageCacheResult::DataAvailable(img_or_meta) => match img_or_meta {
|
||||||
ImageOrMetadataAvailable::ImageAvailable { image, .. } => {
|
ImageOrMetadataAvailable::ImageAvailable { image, .. } => {
|
||||||
|
@ -280,6 +286,7 @@ impl ImageResolver {
|
||||||
node,
|
node,
|
||||||
image_url.clone().into(),
|
image_url.clone().into(),
|
||||||
UsePlaceholder::No,
|
UsePlaceholder::No,
|
||||||
|
LayoutImageDestination::DisplayListBuilding,
|
||||||
)?;
|
)?;
|
||||||
let metadata = image.metadata();
|
let metadata = image.metadata();
|
||||||
let size = Size2D::new(metadata.width, metadata.height).to_f32();
|
let size = Size2D::new(metadata.width, metadata.height).to_f32();
|
||||||
|
|
|
@ -539,6 +539,10 @@ impl Layout for LayoutThread {
|
||||||
self.need_new_display_list.get()
|
self.need_new_display_list.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_needs_new_display_list(&self) {
|
||||||
|
self.need_new_display_list.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
/// <https://drafts.css-houdini.org/css-properties-values-api-1/#the-registerproperty-function>
|
/// <https://drafts.css-houdini.org/css-properties-values-api-1/#the-registerproperty-function>
|
||||||
fn register_custom_property(
|
fn register_custom_property(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
|
@ -7,8 +7,8 @@ use base::id::{BrowsingContextId, PipelineId};
|
||||||
use data_url::DataUrl;
|
use data_url::DataUrl;
|
||||||
use embedder_traits::ViewportDetails;
|
use embedder_traits::ViewportDetails;
|
||||||
use euclid::{Scale, Size2D};
|
use euclid::{Scale, Size2D};
|
||||||
use layout_api::IFrameSize;
|
|
||||||
use layout_api::wrapper_traits::ThreadSafeLayoutNode;
|
use layout_api::wrapper_traits::ThreadSafeLayoutNode;
|
||||||
|
use layout_api::{IFrameSize, LayoutImageDestination};
|
||||||
use malloc_size_of_derive::MallocSizeOf;
|
use malloc_size_of_derive::MallocSizeOf;
|
||||||
use net_traits::image_cache::{Image, ImageOrMetadataAvailable, UsePlaceholder, VectorImage};
|
use net_traits::image_cache::{Image, ImageOrMetadataAvailable, UsePlaceholder, VectorImage};
|
||||||
use script::layout_dom::ServoThreadSafeLayoutNode;
|
use script::layout_dom::ServoThreadSafeLayoutNode;
|
||||||
|
@ -189,7 +189,12 @@ impl ReplacedContents {
|
||||||
|
|
||||||
let result = context
|
let result = context
|
||||||
.image_resolver
|
.image_resolver
|
||||||
.get_cached_image_for_url(node.opaque(), svg_source, UsePlaceholder::No)
|
.get_cached_image_for_url(
|
||||||
|
node.opaque(),
|
||||||
|
svg_source,
|
||||||
|
UsePlaceholder::No,
|
||||||
|
LayoutImageDestination::BoxTreeConstruction,
|
||||||
|
)
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
let vector_image = result.map(|result| match result {
|
let vector_image = result.map(|result| match result {
|
||||||
|
@ -230,6 +235,7 @@ impl ReplacedContents {
|
||||||
node.opaque(),
|
node.opaque(),
|
||||||
image_url.clone().into(),
|
image_url.clone().into(),
|
||||||
UsePlaceholder::No,
|
UsePlaceholder::No,
|
||||||
|
LayoutImageDestination::BoxTreeConstruction,
|
||||||
) {
|
) {
|
||||||
LayoutImageCacheResult::DataAvailable(img_or_meta) => match img_or_meta {
|
LayoutImageCacheResult::DataAvailable(img_or_meta) => match img_or_meta {
|
||||||
ImageOrMetadataAvailable::ImageAvailable { image, .. } => {
|
ImageOrMetadataAvailable::ImageAvailable { image, .. } => {
|
||||||
|
|
|
@ -55,9 +55,10 @@ use js::rust::{
|
||||||
};
|
};
|
||||||
use layout_api::{
|
use layout_api::{
|
||||||
BoxAreaType, ElementsFromPointFlags, ElementsFromPointResult, FragmentType, Layout,
|
BoxAreaType, ElementsFromPointFlags, ElementsFromPointResult, FragmentType, Layout,
|
||||||
PendingImage, PendingImageState, PendingRasterizationImage, QueryMsg, ReflowGoal,
|
LayoutImageDestination, PendingImage, PendingImageState, PendingRasterizationImage, QueryMsg,
|
||||||
ReflowPhasesRun, ReflowRequest, ReflowRequestRestyle, RestyleReason, ScrollContainerQueryType,
|
ReflowGoal, ReflowPhasesRun, ReflowRequest, ReflowRequestRestyle, RestyleReason,
|
||||||
ScrollContainerResponse, TrustedNodeAddress, combine_id_with_fragment_type,
|
ScrollContainerQueryType, ScrollContainerResponse, TrustedNodeAddress,
|
||||||
|
combine_id_with_fragment_type,
|
||||||
};
|
};
|
||||||
use malloc_size_of::MallocSizeOf;
|
use malloc_size_of::MallocSizeOf;
|
||||||
use media::WindowGLContext;
|
use media::WindowGLContext;
|
||||||
|
@ -235,6 +236,17 @@ pub(crate) struct OngoingNavigation(u32);
|
||||||
|
|
||||||
type PendingImageRasterizationKey = (PendingImageId, DeviceIntSize);
|
type PendingImageRasterizationKey = (PendingImageId, DeviceIntSize);
|
||||||
|
|
||||||
|
/// Ancillary data of pending image request that was initiated by layout during a reflow.
|
||||||
|
/// This data is used to faciliate invalidating layout when the image data becomes available
|
||||||
|
/// at some point in the future.
|
||||||
|
#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
|
||||||
|
#[derive(JSTraceable, MallocSizeOf)]
|
||||||
|
struct PendingLayoutImageAncillaryData {
|
||||||
|
node: Dom<Node>,
|
||||||
|
#[no_trace]
|
||||||
|
destination: LayoutImageDestination,
|
||||||
|
}
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub(crate) struct Window {
|
pub(crate) struct Window {
|
||||||
globalscope: GlobalScope,
|
globalscope: GlobalScope,
|
||||||
|
@ -360,7 +372,8 @@ pub(crate) struct Window {
|
||||||
/// initiated by layout during a reflow. They are stored in the [`ScriptThread`]
|
/// initiated by layout during a reflow. They are stored in the [`ScriptThread`]
|
||||||
/// to ensure that the element can be marked dirty when the image data becomes
|
/// to ensure that the element can be marked dirty when the image data becomes
|
||||||
/// available at some point in the future.
|
/// available at some point in the future.
|
||||||
pending_layout_images: DomRefCell<HashMapTracedValues<PendingImageId, Vec<Dom<Node>>>>,
|
pending_layout_images:
|
||||||
|
DomRefCell<HashMapTracedValues<PendingImageId, Vec<PendingLayoutImageAncillaryData>>>,
|
||||||
|
|
||||||
/// Vector images for which layout has intiated rasterization at a specific size
|
/// Vector images for which layout has intiated rasterization at a specific size
|
||||||
/// and whose results are not yet available. They are stored in the [`ScriptThread`]
|
/// and whose results are not yet available. They are stored in the [`ScriptThread`]
|
||||||
|
@ -643,11 +656,22 @@ impl Window {
|
||||||
Entry::Occupied(nodes) => nodes,
|
Entry::Occupied(nodes) => nodes,
|
||||||
Entry::Vacant(_) => return,
|
Entry::Vacant(_) => return,
|
||||||
};
|
};
|
||||||
if matches!(response.response, ImageResponse::Loaded(_, _)) {
|
if matches!(
|
||||||
for node in nodes.get() {
|
response.response,
|
||||||
node.dirty(NodeDamage::Other);
|
ImageResponse::Loaded(_, _) | ImageResponse::PlaceholderLoaded(_, _)
|
||||||
|
) {
|
||||||
|
for ancillary_data in nodes.get() {
|
||||||
|
match ancillary_data.destination {
|
||||||
|
LayoutImageDestination::BoxTreeConstruction => {
|
||||||
|
ancillary_data.node.dirty(NodeDamage::Other);
|
||||||
|
},
|
||||||
|
LayoutImageDestination::DisplayListBuilding => {
|
||||||
|
self.layout().set_needs_new_display_list();
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match response.response {
|
match response.response {
|
||||||
ImageResponse::MetadataLoaded(_) => {},
|
ImageResponse::MetadataLoaded(_) => {},
|
||||||
ImageResponse::Loaded(_, _) |
|
ImageResponse::Loaded(_, _) |
|
||||||
|
@ -3106,8 +3130,11 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
let nodes = images.entry(id).or_default();
|
let nodes = images.entry(id).or_default();
|
||||||
if !nodes.iter().any(|n| std::ptr::eq(&**n, &*node)) {
|
if !nodes.iter().any(|n| std::ptr::eq(&*(n.node), &*node)) {
|
||||||
nodes.push(Dom::from_ref(&*node));
|
nodes.push(PendingLayoutImageAncillaryData {
|
||||||
|
node: Dom::from_ref(&*node),
|
||||||
|
destination: image.destination,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -154,6 +154,13 @@ pub enum PendingImageState {
|
||||||
PendingResponse,
|
PendingResponse,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The destination in layout where an image is needed.
|
||||||
|
#[derive(Debug, MallocSizeOf)]
|
||||||
|
pub enum LayoutImageDestination {
|
||||||
|
BoxTreeConstruction,
|
||||||
|
DisplayListBuilding,
|
||||||
|
}
|
||||||
|
|
||||||
/// The data associated with an image that is not yet present in the image cache.
|
/// The data associated with an image that is not yet present in the image cache.
|
||||||
/// Used by the script thread to hold on to DOM elements that need to be repainted
|
/// Used by the script thread to hold on to DOM elements that need to be repainted
|
||||||
/// when an image fetch is complete.
|
/// when an image fetch is complete.
|
||||||
|
@ -163,6 +170,7 @@ pub struct PendingImage {
|
||||||
pub node: UntrustedNodeAddress,
|
pub node: UntrustedNodeAddress,
|
||||||
pub id: PendingImageId,
|
pub id: PendingImageId,
|
||||||
pub origin: ImmutableOrigin,
|
pub origin: ImmutableOrigin,
|
||||||
|
pub destination: LayoutImageDestination,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A data structure to tarck vector image that are fully loaded (i.e has a parsed SVG
|
/// A data structure to tarck vector image that are fully loaded (i.e has a parsed SVG
|
||||||
|
@ -290,6 +298,9 @@ pub trait Layout {
|
||||||
/// Returns true if this layout needs to produce a new display list for rendering updates.
|
/// Returns true if this layout needs to produce a new display list for rendering updates.
|
||||||
fn needs_new_display_list(&self) -> bool;
|
fn needs_new_display_list(&self) -> bool;
|
||||||
|
|
||||||
|
/// Marks that this layout needs to produce a new display list for rendering updates.
|
||||||
|
fn set_needs_new_display_list(&self);
|
||||||
|
|
||||||
fn query_box_area(&self, node: TrustedNodeAddress, area: BoxAreaType) -> Option<Rect<Au>>;
|
fn query_box_area(&self, node: TrustedNodeAddress, area: BoxAreaType) -> Option<Rect<Au>>;
|
||||||
fn query_box_areas(&self, node: TrustedNodeAddress, area: BoxAreaType) -> Vec<Rect<Au>>;
|
fn query_box_areas(&self, node: TrustedNodeAddress, area: BoxAreaType) -> Vec<Rect<Au>>;
|
||||||
fn query_client_rect(&self, node: TrustedNodeAddress) -> Rect<i32>;
|
fn query_client_rect(&self, node: TrustedNodeAddress) -> Rect<i32>;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue