Skip to content

Commit dbe17a6

Browse files
committed
working cached impl
1 parent 2923d17 commit dbe17a6

File tree

7 files changed

+118
-17
lines changed

7 files changed

+118
-17
lines changed

components/layout/context.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44

55
use std::sync::Arc;
66

7+
use embedder_traits::UntrustedNodeAddress;
78
use euclid::Size2D;
89
use fnv::FnvHashMap;
10+
use style::dom::TNode;
911
use fonts::FontContext;
1012
use fxhash::FxHashMap;
1113
use layout_api::{
@@ -86,6 +88,7 @@ pub(crate) struct ImageResolver {
8688
/// size determined by layout. This will be shared with the script thread.
8789
pub pending_rasterization_images: Mutex<Vec<PendingRasterizationImage>>,
8890

91+
pub pending_svg_element_for_serialization: Mutex<Vec<UntrustedNodeAddress>>,
8992
/// A shared reference to script's map of DOM nodes with animated images. This is used
9093
/// to manage image animations in script and inform the script about newly animating
9194
/// nodes.
@@ -104,7 +107,8 @@ impl Drop for ImageResolver {
104107
fn drop(&mut self) {
105108
if !std::thread::panicking() {
106109
assert!(self.pending_images.lock().is_empty());
107-
assert!(self.pending_rasterization_images.lock().is_empty());
110+
assert!(self.pending_images.lock().is_empty());
111+
assert!(self.pending_svg_element_for_serialization.lock().is_empty());
108112
}
109113
}
110114
}
@@ -174,7 +178,7 @@ impl ImageResolver {
174178
}
175179
}
176180

177-
fn get_cached_image_for_url(
181+
pub(crate) fn get_cached_image_for_url(
178182
&self,
179183
node: OpaqueNode,
180184
url: ServoUrl,
@@ -234,6 +238,15 @@ impl ImageResolver {
234238
result
235239
}
236240

241+
pub(crate) fn queue_svg_element_for_serialization(
242+
&self,
243+
element: script::layout_dom::ServoLayoutNode<'_>,
244+
) {
245+
self.pending_svg_element_for_serialization
246+
.lock()
247+
.push(element.opaque().into())
248+
}
249+
237250
pub(crate) fn resolve_image<'a>(
238251
&self,
239252
node: Option<OpaqueNode>,

components/layout/dom.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ use std::marker::PhantomData;
77

88
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
99
use base::id::{BrowsingContextId, PipelineId};
10-
use html5ever::{local_name, ns};
1110
use html5ever::serialize::Serializer;
11+
use html5ever::{local_name, ns};
1212
use layout_api::wrapper_traits::{
1313
LayoutDataTrait, LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
1414
};
1515
use layout_api::{
16-
GenericLayoutDataTrait, LayoutDamage, LayoutElementType, LayoutNodeType as ScriptLayoutNodeType, SVGSVGData,
16+
GenericLayoutDataTrait, LayoutDamage, LayoutElementType,
17+
LayoutNodeType as ScriptLayoutNodeType, SVGSVGData,
1718
};
1819
use malloc_size_of_derive::MallocSizeOf;
1920
use net_traits::image_cache::Image;
@@ -279,8 +280,8 @@ impl<'dom> NodeExt<'dom> for ServoLayoutNode<'dom> {
279280
let node = self.to_threadsafe();
280281
let svg_data = node.svg_data()?;
281282
let width = svg_data.width as f64;
282-
let height= svg_data.height as f64;
283-
println!("SVG Source {:?}", svg_data.source);
283+
let height = svg_data.height as f64;
284+
//println!("SVG Source {:?}", svg_data.source);
284285
Some((svg_data, PhysicalSize::new(width, height)))
285286
}
286287

components/layout/layout_impl.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,7 @@ impl LayoutThread {
660660
resolved_images_cache: self.resolved_images_cache.clone(),
661661
pending_images: Mutex::default(),
662662
pending_rasterization_images: Mutex::default(),
663+
pending_svg_element_for_serialization: Mutex::default(),
663664
node_to_animating_image_map: reflow_request.node_to_animating_image_map.clone(),
664665
animation_timeline_value: reflow_request.animation_timeline_value,
665666
});
@@ -682,11 +683,14 @@ impl LayoutThread {
682683
let pending_images = std::mem::take(&mut *image_resolver.pending_images.lock());
683684
let pending_rasterization_images =
684685
std::mem::take(&mut *image_resolver.pending_rasterization_images.lock());
686+
let pending_svg_element_for_serialization =
687+
std::mem::take(&mut *image_resolver.pending_svg_element_for_serialization.lock());
685688

686689
Some(ReflowResult {
687690
built_display_list,
688691
pending_images,
689692
pending_rasterization_images,
693+
pending_svg_element_for_serialization,
690694
iframe_sizes,
691695
})
692696
}

components/layout/replaced.rs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use malloc_size_of_derive::MallocSizeOf;
1212
use net_traits::image_cache::{Image, ImageOrMetadataAvailable, UsePlaceholder};
1313
use script::layout_dom::ServoLayoutNode;
1414
use servo_arc::Arc as ServoArc;
15+
use servo_url::ServoUrl;
1516
use style::Zero;
1617
use style::computed_values::object_fit::T as ObjectFit;
1718
use style::dom::TNode;
@@ -115,7 +116,7 @@ pub(crate) enum ReplacedContentKind {
115116
IFrame(IFrameInfo),
116117
Canvas(CanvasInfo),
117118
Video(Option<VideoInfo>),
118-
SVGElement,
119+
SVGElement(Image),
119120
}
120121

121122
impl ReplacedContents {
@@ -154,8 +155,20 @@ impl ReplacedContents {
154155
ReplacedContentKind::Video(image_key.map(|key| VideoInfo { image_key: key })),
155156
natural_size_in_dots,
156157
)
157-
} else if let Some(_) = element.as_svg() {
158-
(ReplacedContentKind::SVGElement, None)
158+
} else if let Some((svg_data, _)) = element.as_svg() {
159+
let Some(svg_source) = svg_data.source else {
160+
context.image_resolver.queue_svg_element_for_serialization(element);
161+
return None;
162+
};
163+
let result = context
164+
.image_resolver
165+
.get_cached_image_for_url(element.opaque(), svg_source, UsePlaceholder::Yes)
166+
.ok()?;
167+
let size = result.metadata();
168+
(
169+
ReplacedContentKind::SVGElement(result),
170+
Some(PhysicalSize::new(size.width as f64, size.height as f64)),
171+
)
159172
} else {
160173
return None;
161174
}
@@ -393,10 +406,36 @@ impl ReplacedContents {
393406
image_key: Some(image_key),
394407
}))]
395408
},
396-
ReplacedContentKind::SVGElement => {
409+
ReplacedContentKind::SVGElement(image) => {
397410
println!("ReplacedContentKind::SVG Encountered");
398-
vec![]
399-
}
411+
let id = match image {
412+
Image::Raster(raster_image) => {
413+
unreachable!("SVG Element can't contain a raster")
414+
},
415+
Image::Vector(vector_image) => {
416+
let scale = layout_context.style_context.device_pixel_ratio();
417+
let width = object_fit_size.width.scale_by(scale.0).to_px();
418+
let height = object_fit_size.height.scale_by(scale.0).to_px();
419+
let size = Size2D::new(width, height);
420+
let tag = self.base_fragment_info.tag.unwrap();
421+
layout_context
422+
.image_resolver
423+
.rasterize_vector_image(vector_image.id, size, tag.node)
424+
.and_then(|i| i.id)
425+
},
426+
};
427+
id.map(|image_key| {
428+
Fragment::Image(ArcRefCell::new(ImageFragment {
429+
base: self.base_fragment_info.into(),
430+
style: style.clone(),
431+
rect,
432+
clip,
433+
image_key: Some(image_key),
434+
}))
435+
})
436+
.into_iter()
437+
.collect()
438+
},
400439
}
401440
}
402441

components/script/dom/svgsvgelement.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
44

5+
use std::cell::RefCell;
6+
7+
use base64::Engine as _;
58
use dom_struct::dom_struct;
69
use html5ever::{LocalName, Prefix, local_name, ns};
710
use js::rust::HandleObject;
811
use layout_api::SVGSVGData;
12+
use servo_url::ServoUrl;
913
use style::attr::AttrValue;
14+
use xml5ever::serialize::TraversalScope;
1015

1116
use crate::dom::attr::Attr;
1217
use crate::dom::bindings::inheritance::Castable;
@@ -25,6 +30,8 @@ const DEFAULT_HEIGHT: u32 = 150;
2530
#[dom_struct]
2631
pub(crate) struct SVGSVGElement {
2732
svggraphicselement: SVGGraphicsElement,
33+
#[no_trace]
34+
cached_serialized_data: RefCell<Option<ServoUrl>>,
2835
}
2936

3037
impl SVGSVGElement {
@@ -35,6 +42,7 @@ impl SVGSVGElement {
3542
) -> SVGSVGElement {
3643
SVGSVGElement {
3744
svggraphicselement: SVGGraphicsElement::new_inherited(local_name, prefix, document),
45+
cached_serialized_data: Default::default(),
3846
}
3947
}
4048

@@ -53,6 +61,19 @@ impl SVGSVGElement {
5361
can_gc,
5462
)
5563
}
64+
65+
pub(crate) fn cache_serialized_data(&self) {
66+
println!("XXX cache_serialized_data");
67+
let source: String = self
68+
.upcast::<Node>()
69+
.xml_serialize(TraversalScope::IncludeNode)
70+
.into();
71+
let base64 = base64::engine::general_purpose::STANDARD.encode(source);
72+
let source = format!("data:image/svg+xml;base64,{}", base64);
73+
if let Ok(url) = ServoUrl::parse(&source) {
74+
*self.cached_serialized_data.borrow_mut() = Some(url);
75+
}
76+
}
5677
}
5778

5879
pub(crate) trait LayoutSVGSVGElementHelpers {
@@ -70,7 +91,7 @@ impl LayoutSVGSVGElementHelpers for LayoutDom<'_, SVGSVGElement> {
7091
SVGSVGData {
7192
width: width_attr.map_or(DEFAULT_WIDTH, |val| val.as_uint()),
7293
height: height_attr.map_or(DEFAULT_HEIGHT, |val| val.as_uint()),
73-
source: self.upcast::<Element>().serialize_as_xml().into()
94+
source: self.unsafe_get().cached_serialized_data.borrow().clone(),
7495
}
7596
}
7697
}
@@ -84,6 +105,7 @@ impl VirtualMethods for SVGSVGElement {
84105
self.super_type()
85106
.unwrap()
86107
.attribute_mutated(attr, mutation, can_gc);
108+
*self.cached_serialized_data.borrow_mut() = None;
87109
}
88110

89111
fn parse_plain_attribute(&self, name: &LocalName, value: DOMString) -> AttrValue {
@@ -96,4 +118,17 @@ impl VirtualMethods for SVGSVGElement {
96118
.parse_plain_attribute(name, value),
97119
}
98120
}
121+
122+
// fn children_changed(&self, mutation: &super::node::ChildrenMutation) {
123+
// self.super_type()
124+
// .map(|parent| parent.children_changed(mutation));
125+
// println!("XXX children_changed");
126+
// let source: String = self
127+
// .upcast::<Node>()
128+
// .html_serialize(TraversalScope::IncludeNode, false, vec![], CanGc::note())
129+
// .into();
130+
// let base64 = base64::engine::general_purpose::STANDARD.encode(source);
131+
// let source = format!("data:image/svg+xml;base64,{}", base64);
132+
// *self.serialized_data_url.borrow_mut() = source;
133+
// }
99134
}

components/script/dom/window.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,7 @@ use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarker
3232
use dom_struct::dom_struct;
3333
use embedder_traits::user_content_manager::{UserContentManager, UserScript};
3434
use embedder_traits::{
35-
AlertResponse, ConfirmResponse, EmbedderMsg, GamepadEvent, GamepadSupportedHapticEffects,
36-
GamepadUpdateType, PromptResponse, SimpleDialog, Theme, ViewportDetails, WebDriverJSError,
37-
WebDriverJSResult,
35+
AlertResponse, ConfirmResponse, EmbedderMsg, GamepadEvent, GamepadSupportedHapticEffects, GamepadUpdateType, PromptResponse, SimpleDialog, Theme, UntrustedNodeAddress, ViewportDetails, WebDriverJSError, WebDriverJSResult
3836
};
3937
use euclid::default::{Point2D as UntypedPoint2D, Rect as UntypedRect, Size2D as UntypedSize2D};
4038
use euclid::{Point2D, Scale, Size2D, Vector2D};
@@ -92,6 +90,7 @@ use webrender_api::units::{DeviceIntSize, DevicePixel, LayoutPixel};
9290

9391
use super::bindings::codegen::Bindings::MessagePortBinding::StructuredSerializeOptions;
9492
use super::bindings::trace::HashMapTracedValues;
93+
use super::types::SVGSVGElement;
9594
use crate::dom::bindings::cell::{DomRefCell, Ref};
9695
use crate::dom::bindings::codegen::Bindings::DocumentBinding::{
9796
DocumentMethods, DocumentReadyState, NamedPropertyValue,
@@ -2258,6 +2257,7 @@ impl Window {
22582257
self.handle_pending_images_post_reflow(
22592258
results.pending_images,
22602259
results.pending_rasterization_images,
2260+
results.pending_svg_element_for_serialization
22612261
);
22622262
document
22632263
.iframes_mut()
@@ -2989,6 +2989,7 @@ impl Window {
29892989
&self,
29902990
pending_images: Vec<PendingImage>,
29912991
pending_rasterization_images: Vec<PendingRasterizationImage>,
2992+
pending_svg_element_for_serialization: Vec<UntrustedNodeAddress>,
29922993
) {
29932994
let pipeline_id = self.pipeline_id();
29942995
for image in pending_images {
@@ -3037,6 +3038,13 @@ impl Window {
30373038
nodes.push(Dom::from_ref(&*node));
30383039
}
30393040
}
3041+
3042+
for node in pending_svg_element_for_serialization.into_iter() {
3043+
let node = unsafe { from_untrusted_node_address(node) };
3044+
let svg = node.downcast::<SVGSVGElement>().unwrap();
3045+
svg.cache_serialized_data();
3046+
node.dirty(NodeDamage::Other);
3047+
}
30403048
}
30413049
}
30423050

components/shared/layout/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ pub struct HTMLCanvasData {
132132
pub struct SVGSVGData {
133133
pub width: u32,
134134
pub height: u32,
135-
pub source: String
135+
pub source: Option<ServoUrl>
136136
}
137137

138138
/// The address of a node known to be valid. These are sent from script to layout.
@@ -390,6 +390,7 @@ pub struct ReflowResult {
390390
pub pending_images: Vec<PendingImage>,
391391
/// The list of vector images that were encountered that still need to be rasterized.
392392
pub pending_rasterization_images: Vec<PendingRasterizationImage>,
393+
pub pending_svg_element_for_serialization: Vec<UntrustedNodeAddress>,
393394
/// The list of iframes in this layout and their sizes, used in order
394395
/// to communicate them with the Constellation and also the `Window`
395396
/// element of their content pages.

0 commit comments

Comments
 (0)