Auto merge of #21931 - jdm:reload-images, r=emilio

Make layout use available image data before querying the image cache.

These changes make layout more efficient for any page which contains images that have already loaded, since it does not require synchronously querying the image cache thread for each image present. It also makes reloading a page actually display the images that are already in the image cache.

---
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix #21919
- [x] There are tests for these changes

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/21931)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-10-13 07:56:11 -04:00 committed by GitHub
commit e4657c1496
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 102 additions and 5 deletions

View file

@ -401,6 +401,11 @@ pub struct ImageFragmentInfo {
pub metadata: Option<ImageMetadata>, pub metadata: Option<ImageMetadata>,
} }
enum ImageOrMetadata {
Image(Arc<Image>),
Metadata(ImageMetadata),
}
impl ImageFragmentInfo { impl ImageFragmentInfo {
/// Creates a new image fragment from the given URL and local image cache. /// Creates a new image fragment from the given URL and local image cache.
/// ///
@ -412,14 +417,29 @@ impl ImageFragmentInfo {
node: &N, node: &N,
layout_context: &LayoutContext, layout_context: &LayoutContext,
) -> ImageFragmentInfo { ) -> ImageFragmentInfo {
let image_or_metadata = url.and_then(|url| { // First use any image data present in the element...
layout_context.get_or_request_image_or_meta(node.opaque(), url, UsePlaceholder::Yes) let image_or_metadata = node.image_data().and_then(|(image, metadata)| {
}); match (image, metadata) {
(Some(image), _) => Some(ImageOrMetadata::Image(image)),
(None, Some(metadata)) => Some(ImageOrMetadata::Metadata(metadata)),
_ => None,
}
}).or_else(|| url.and_then(|url| {
// Otherwise query the image cache for anything known about the associated source URL.
layout_context.get_or_request_image_or_meta(
node.opaque(),
url,
UsePlaceholder::Yes
).map(|result| match result {
ImageOrMetadataAvailable::ImageAvailable(i, _) => ImageOrMetadata::Image(i),
ImageOrMetadataAvailable::MetadataAvailable(m) => ImageOrMetadata::Metadata(m),
})
}));
let current_pixel_density = density.unwrap_or(1f64); let current_pixel_density = density.unwrap_or(1f64);
let (image, metadata) = match image_or_metadata { let (image, metadata) = match image_or_metadata {
Some(ImageOrMetadataAvailable::ImageAvailable(i, _)) => { Some(ImageOrMetadata::Image(i)) => {
let height = (i.height as f64 / current_pixel_density) as u32; let height = (i.height as f64 / current_pixel_density) as u32;
let width = (i.width as f64 / current_pixel_density) as u32; let width = (i.width as f64 / current_pixel_density) as u32;
( (
@ -434,7 +454,7 @@ impl ImageFragmentInfo {
}), }),
) )
}, },
Some(ImageOrMetadataAvailable::MetadataAvailable(m)) => { Some(ImageOrMetadata::Metadata(m)) => {
( (
None, None,
Some(ImageMetadata { Some(ImageMetadata {

View file

@ -36,6 +36,7 @@ use html5ever::{LocalName, Namespace};
use layout::data::StyleAndLayoutData; use layout::data::StyleAndLayoutData;
use layout::wrapper::GetRawData; use layout::wrapper::GetRawData;
use msg::constellation_msg::{BrowsingContextId, PipelineId}; use msg::constellation_msg::{BrowsingContextId, PipelineId};
use net_traits::image::base::{Image, ImageMetadata};
use range::Range; use range::Range;
use script::layout_exports::{CharacterDataTypeId, ElementTypeId, HTMLElementTypeId, NodeTypeId}; use script::layout_exports::{CharacterDataTypeId, ElementTypeId, HTMLElementTypeId, NodeTypeId};
use script::layout_exports::{Document, Element, Node, Text}; use script::layout_exports::{Document, Element, Node, Text};
@ -59,6 +60,7 @@ use std::fmt::Debug;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ptr::NonNull; use std::ptr::NonNull;
use std::sync::Arc as StdArc;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use style::CaseSensitivityExt; use style::CaseSensitivityExt;
use style::applicable_declarations::ApplicableDeclarationBlock; use style::applicable_declarations::ApplicableDeclarationBlock;
@ -1048,6 +1050,11 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> {
this.image_density() this.image_density()
} }
fn image_data(&self) -> Option<(Option<StdArc<Image>>, Option<ImageMetadata>)> {
let this = unsafe { self.get_jsmanaged() };
this.image_data()
}
fn canvas_data(&self) -> Option<HTMLCanvasData> { fn canvas_data(&self) -> Option<HTMLCanvasData> {
let this = unsafe { self.get_jsmanaged() }; let this = unsafe { self.get_jsmanaged() };
this.canvas_data() this.canvas_data()

View file

@ -1328,6 +1328,9 @@ pub trait LayoutHTMLImageElementHelpers {
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe fn image_density(&self) -> Option<f64>; unsafe fn image_density(&self) -> Option<f64>;
#[allow(unsafe_code)]
unsafe fn image_data(&self) -> (Option<Arc<Image>>, Option<ImageMetadata>);
fn get_width(&self) -> LengthOrPercentageOrAuto; fn get_width(&self) -> LengthOrPercentageOrAuto;
fn get_height(&self) -> LengthOrPercentageOrAuto; fn get_height(&self) -> LengthOrPercentageOrAuto;
} }
@ -1351,6 +1354,14 @@ impl LayoutHTMLImageElementHelpers for LayoutDom<HTMLImageElement> {
.clone() .clone()
} }
#[allow(unsafe_code)]
unsafe fn image_data(&self) -> (Option<Arc<Image>>, Option<ImageMetadata>) {
let current_request = (*self.unsafe_get())
.current_request
.borrow_for_layout();
(current_request.image.clone(), current_request.metadata.clone())
}
#[allow(unsafe_code)] #[allow(unsafe_code)]
unsafe fn image_density(&self) -> Option<f64> { unsafe fn image_density(&self) -> Option<f64> {
(*self.unsafe_get()) (*self.unsafe_get())

View file

@ -62,6 +62,7 @@ use js::jsapi::{JSContext, JSObject, JSRuntime};
use libc::{self, c_void, uintptr_t}; use libc::{self, c_void, uintptr_t};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use msg::constellation_msg::{BrowsingContextId, PipelineId}; use msg::constellation_msg::{BrowsingContextId, PipelineId};
use net_traits::image::base::{Image, ImageMetadata};
use ref_slice::ref_slice; use ref_slice::ref_slice;
use script_layout_interface::{HTMLCanvasData, HTMLMediaData, LayoutElementType, LayoutNodeType}; use script_layout_interface::{HTMLCanvasData, HTMLMediaData, LayoutElementType, LayoutNodeType};
use script_layout_interface::{OpaqueStyleAndLayoutData, SVGSVGData, TrustedNodeAddress}; use script_layout_interface::{OpaqueStyleAndLayoutData, SVGSVGData, TrustedNodeAddress};
@ -81,6 +82,7 @@ use std::default::Default;
use std::iter; use std::iter;
use std::mem; use std::mem;
use std::ops::Range; use std::ops::Range;
use std::sync::Arc as StdArc;
use style::context::QuirksMode; use style::context::QuirksMode;
use style::dom::OpaqueNode; use style::dom::OpaqueNode;
use style::selector_parser::{SelectorImpl, SelectorParser}; use style::selector_parser::{SelectorImpl, SelectorParser};
@ -1086,6 +1088,7 @@ pub trait LayoutNodeHelpers {
fn selection(&self) -> Option<Range<usize>>; fn selection(&self) -> Option<Range<usize>>;
fn image_url(&self) -> Option<ServoUrl>; fn image_url(&self) -> Option<ServoUrl>;
fn image_density(&self) -> Option<f64>; fn image_density(&self) -> Option<f64>;
fn image_data(&self) -> Option<(Option<StdArc<Image>>, Option<ImageMetadata>)>;
fn canvas_data(&self) -> Option<HTMLCanvasData>; fn canvas_data(&self) -> Option<HTMLCanvasData>;
fn media_data(&self) -> Option<HTMLMediaData>; fn media_data(&self) -> Option<HTMLMediaData>;
fn svg_data(&self) -> Option<SVGSVGData>; fn svg_data(&self) -> Option<SVGSVGData>;
@ -1233,6 +1236,13 @@ impl LayoutNodeHelpers for LayoutDom<Node> {
} }
} }
#[allow(unsafe_code)]
fn image_data(&self) -> Option<(Option<StdArc<Image>>, Option<ImageMetadata>)> {
unsafe {
self.downcast::<HTMLImageElement>().map(|e| e.image_data())
}
}
#[allow(unsafe_code)] #[allow(unsafe_code)]
fn image_density(&self) -> Option<f64> { fn image_density(&self) -> Option<f64> {
unsafe { unsafe {

View file

@ -13,10 +13,12 @@ use atomic_refcell::AtomicRef;
use gfx_traits::{ByteIndex, FragmentType, combine_id_with_fragment_type}; use gfx_traits::{ByteIndex, FragmentType, combine_id_with_fragment_type};
use html5ever::{Namespace, LocalName}; use html5ever::{Namespace, LocalName};
use msg::constellation_msg::{BrowsingContextId, PipelineId}; use msg::constellation_msg::{BrowsingContextId, PipelineId};
use net_traits::image::base::{Image, ImageMetadata};
use range::Range; use range::Range;
use servo_arc::Arc; use servo_arc::Arc;
use servo_url::ServoUrl; use servo_url::ServoUrl;
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::Arc as StdArc;
use style::attr::AttrValue; use style::attr::AttrValue;
use style::context::SharedStyleContext; use style::context::SharedStyleContext;
use style::data::ElementData; use style::data::ElementData;
@ -276,6 +278,9 @@ pub trait ThreadSafeLayoutNode:
/// If this is an image element, returns its current-pixel-density. If this is not an image element, fails. /// If this is an image element, returns its current-pixel-density. If this is not an image element, fails.
fn image_density(&self) -> Option<f64>; fn image_density(&self) -> Option<f64>;
/// If this is an image element, returns its image data. Otherwise, returns `None`.
fn image_data(&self) -> Option<(Option<StdArc<Image>>, Option<ImageMetadata>)>;
fn canvas_data(&self) -> Option<HTMLCanvasData>; fn canvas_data(&self) -> Option<HTMLCanvasData>;
fn svg_data(&self) -> Option<SVGSVGData>; fn svg_data(&self) -> Option<SVGSVGData>;

View file

@ -188281,6 +188281,18 @@
{} {}
] ]
], ],
"html/semantics/embedded-content/the-img-element/available-images.html": [
[
"/html/semantics/embedded-content/the-img-element/available-images.html",
[
[
"/html/semantics/embedded-content/the-img-element/available-images-ref.html",
"=="
]
],
{}
]
],
"html/semantics/embedded-content/the-img-element/document-adopt-base-url.html": [ "html/semantics/embedded-content/the-img-element/document-adopt-base-url.html": [
[ [
"/html/semantics/embedded-content/the-img-element/document-adopt-base-url.html", "/html/semantics/embedded-content/the-img-element/document-adopt-base-url.html",
@ -292044,6 +292056,11 @@
{} {}
] ]
], ],
"html/semantics/embedded-content/the-img-element/available-images-ref.html": [
[
{}
]
],
"html/semantics/embedded-content/the-img-element/brokenimg.jpg": [ "html/semantics/embedded-content/the-img-element/brokenimg.jpg": [
[ [
{} {}
@ -614985,6 +615002,14 @@
"15e02bcf51535d45a702b0977f919eff8ce5ba9c", "15e02bcf51535d45a702b0977f919eff8ce5ba9c",
"testharness" "testharness"
], ],
"html/semantics/embedded-content/the-img-element/available-images-ref.html": [
"8061abae50899a2befe286723d8bd5c285b356ab",
"support"
],
"html/semantics/embedded-content/the-img-element/available-images.html": [
"779ff978689e4f5565b8d45d383efa75ac78b8b2",
"reftest"
],
"html/semantics/embedded-content/the-img-element/brokenimg.jpg": [ "html/semantics/embedded-content/the-img-element/brokenimg.jpg": [
"ccff177ae9b5066a7085f7e967ab869e665975cc", "ccff177ae9b5066a7085f7e967ab869e665975cc",
"support" "support"

View file

@ -0,0 +1,2 @@
<!doctype html>
<img src="3.jpg">

View file

@ -0,0 +1,17 @@
<!doctype html>
<html class="reftest-wait">
<title>Ensure images from available images list are rendered</title>
<meta charset="utf-8">
<link rel="match" href="available-images-ref.html">
<link rel="help" href="https://html.spec.whatwg.org/multipage/#the-img-element">
<div id="log"></div>
<script>
var i = new Image();
i.onload = function() {
var i2 = new Image();
i2.src = "3.jpg";
document.body.appendChild(i2);
document.documentElement.classList.remove("reftest-wait");
};
i.src = "3.jpg";
</script>