From d8aef7208e5ed9705f551f0bf0e0cd6607ff224f Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Mon, 20 Apr 2015 13:34:26 +1000 Subject: [PATCH] Refactored image cache task - details below. * Simpler image cache API for clients to use. * Significantly fewer threads. * One thread for image cache task (multiplexes commands, decoder threads and async resource requests). * 4 threads for decoder worker tasks. * Removed ReflowEvent hacks in script and layout tasks. * Image elements pass a Trusted to image cache, which is used to dirty nodes via script task. Previous use of Untrusted addresses was unsafe. * Image requests such as background-image on layout / paint threads trigger repaint only rather than full reflow. * Add reflow batching for when multiple images load quickly. * Reduces the number of paints loading wikipedia from ~95 to ~35. * Reasonably simple to add proper prefetch support in a follow up PR. * Async loaded images always construct Image fragments now, instead of generic. * Image fragments support the image not being present. * Simpler implementation of synchronous image loading for reftests. * Removed image holder. * image.onload support. * image NaturalWidth and NaturalHeight support. * Updated WPT expectations. --- components/compositing/constellation.rs | 2 +- components/gfx/paint_task.rs | 7 +- components/layout/construct.rs | 35 +- components/layout/context.rs | 54 +- components/layout/display_list_builder.rs | 169 ++--- components/layout/fragment.rs | 45 +- components/layout/layout_task.rs | 119 ++-- components/layout/wrapper.rs | 2 +- components/layout_traits/lib.rs | 2 +- components/net/image_cache_task.rs | 649 ++++++++--------- components/net_traits/image/holder.rs | 100 --- components/net_traits/image_cache_task.rs | 153 ++--- components/net_traits/lib.rs | 3 - components/net_traits/local_image_cache.rs | 170 ----- components/script/dom/bindings/refcounted.rs | 7 +- components/script/dom/bindings/trace.rs | 7 +- .../script/dom/canvasrenderingcontext2d.rs | 15 +- components/script/dom/htmlimageelement.rs | 103 ++- components/script/dom/htmlobjectelement.rs | 23 +- .../dom/webidls/HTMLImageElement.webidl | 6 +- components/script/dom/window.rs | 36 +- components/script/script_task.rs | 86 +-- components/script_traits/lib.rs | 2 - components/servo/lib.rs | 26 +- ports/gonk/src/lib.rs | 16 +- tests/unit/net/image_cache_task.rs | 574 ---------------- tests/unit/net/lib.rs | 1 - .../wpt/metadata/html/dom/interfaces.html.ini | 18 - .../svg-in-img-auto.html.ini | 650 +++++++++++++++++- .../svg-in-img-fixed.html.ini | 648 ++++++++++++++++- .../svg-in-img-percentage.html.ini | 650 +++++++++++++++++- .../relevant-mutations.html.ini | 74 +- .../tests/mozilla/img_width_height.html | 12 +- 33 files changed, 2785 insertions(+), 1679 deletions(-) delete mode 100644 components/net_traits/image/holder.rs delete mode 100644 components/net_traits/local_image_cache.rs delete mode 100644 tests/unit/net/image_cache_task.rs diff --git a/components/compositing/constellation.rs b/components/compositing/constellation.rs index 5867a871096..eb54339d159 100644 --- a/components/compositing/constellation.rs +++ b/components/compositing/constellation.rs @@ -21,7 +21,7 @@ use msg::constellation_msg::{Key, KeyState, KeyModifiers, LoadData}; use msg::constellation_msg::{SubpageId, WindowSizeData}; use msg::constellation_msg::{self, ConstellationChan, Failure}; use net_traits::{self, ResourceTask}; -use net_traits::image_cache_task::{ImageCacheTask, ImageCacheTaskClient}; +use net_traits::image_cache_task::ImageCacheTask; use net_traits::storage_task::{StorageTask, StorageTaskMsg}; use profile::mem; use profile::time; diff --git a/components/gfx/paint_task.rs b/components/gfx/paint_task.rs index e359f73bc79..a97487db92d 100644 --- a/components/gfx/paint_task.rs +++ b/components/gfx/paint_task.rs @@ -27,8 +27,8 @@ use msg::constellation_msg::{ConstellationChan, Failure, PipelineId}; use msg::constellation_msg::PipelineExitType; use profile::time::{self, profile}; use skia::SkiaGrGLNativeContextRef; +use std::borrow::ToOwned; use std::mem; -use std::thread::Builder; use std::sync::Arc; use std::sync::mpsc::{Receiver, Sender, channel}; use util::geometry::{Au, ZERO_POINT}; @@ -36,6 +36,7 @@ use util::opts; use util::smallvec::SmallVec; use util::task::spawn_named_with_send_on_failure; use util::task_state; +use util::task::spawn_named; /// Information about a hardware graphics layer that layout sends to the painting task. #[derive(Clone)] @@ -432,14 +433,14 @@ impl WorkerThreadProxy { let native_graphics_metadata = native_graphics_metadata.clone(); let font_cache_task = font_cache_task.clone(); let time_profiler_chan = time_profiler_chan.clone(); - Builder::new().spawn(move || { + spawn_named("PaintWorker".to_owned(), move || { let mut worker_thread = WorkerThread::new(from_worker_sender, to_worker_receiver, native_graphics_metadata, font_cache_task, time_profiler_chan); worker_thread.main(); - }).unwrap(); + }); WorkerThreadProxy { receiver: from_worker_receiver, sender: to_worker_sender, diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 5ebdc225a7a..8bac5dccb72 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -250,24 +250,6 @@ impl<'a> FlowConstructor<'a> { node.set_flow_construction_result(result); } - /// Builds the `ImageFragmentInfo` for the given image. This is out of line to guide inlining. - fn build_fragment_info_for_image(&mut self, node: &ThreadSafeLayoutNode, url: Option) - -> SpecificFragmentInfo { - match url { - None => SpecificFragmentInfo::Generic, - Some(url) => { - // FIXME(pcwalton): The fact that image fragments store the cache within them makes - // little sense to me. - SpecificFragmentInfo::Image(box ImageFragmentInfo::new(node, - url, - self.layout_context - .shared - .image_cache - .clone())) - } - } - } - /// Builds the fragment for the given block or subclass thereof. fn build_fragment_for_block(&mut self, node: &ThreadSafeLayoutNode) -> Fragment { let specific_fragment_info = match node.type_id() { @@ -277,12 +259,17 @@ impl<'a> FlowConstructor<'a> { } Some(NodeTypeId::Element(ElementTypeId::HTMLElement( HTMLElementTypeId::HTMLImageElement))) => { - self.build_fragment_info_for_image(node, node.image_url()) + let image_info = box ImageFragmentInfo::new(node, + node.image_url(), + &self.layout_context); + SpecificFragmentInfo::Image(image_info) } Some(NodeTypeId::Element(ElementTypeId::HTMLElement( HTMLElementTypeId::HTMLObjectElement))) => { - let data = node.get_object_data(); - self.build_fragment_info_for_image(node, data) + let image_info = box ImageFragmentInfo::new(node, + node.get_object_data(), + &self.layout_context); + SpecificFragmentInfo::Image(image_info) } Some(NodeTypeId::Element(ElementTypeId::HTMLElement( HTMLElementTypeId::HTMLTableElement))) => { @@ -1031,8 +1018,10 @@ impl<'a> FlowConstructor<'a> { }; let marker_fragment = match node.style().get_list().list_style_image { Some(ref url) => { - Some(Fragment::new(node, - self.build_fragment_info_for_image(node, Some((*url).clone())))) + let image_info = box ImageFragmentInfo::new(node, + Some((*url).clone()), + &self.layout_context); + Some(Fragment::new(node, SpecificFragmentInfo::Image(image_info))) } None => { match ListStyleTypeContent::from_list_style_type(node.style() diff --git a/components/layout/context.rs b/components/layout/context.rs index 4d8f161f642..38996d5eea1 100644 --- a/components/layout/context.rs +++ b/components/layout/context.rs @@ -13,17 +13,18 @@ use gfx::display_list::OpaqueNode; use gfx::font_cache_task::FontCacheTask; use gfx::font_context::FontContext; use msg::constellation_msg::ConstellationChan; +use net_traits::image::base::Image; +use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask, ImageState}; use script::layout_interface::{Animation, LayoutChan}; -use script_traits::UntrustedNodeAddress; -use net_traits::local_image_cache::LocalImageCache; use std::boxed; use std::cell::Cell; use std::ptr; -use std::sync::mpsc::Sender; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; +use std::sync::mpsc::{channel, Sender}; use style::selector_matching::Stylist; use url::Url; use util::geometry::Au; +use util::opts; struct LocalLayoutContext { font_context: FontContext, @@ -55,8 +56,11 @@ fn create_or_get_local_context(shared_layout_context: &SharedLayoutContext) /// Layout information shared among all workers. This must be thread-safe. pub struct SharedLayoutContext { - /// The local image cache. - pub image_cache: Arc>>, + /// The shared image cache task. + pub image_cache_task: ImageCacheTask, + + /// A channel for the image cache to send responses to. + pub image_cache_sender: ImageCacheChan, /// The current screen size. pub screen_size: Size2D, @@ -139,4 +143,42 @@ impl<'a> LayoutContext<'a> { &mut cached_context.style_sharing_candidate_cache } } + + pub fn get_or_request_image(&self, url: Url) -> Option> { + // See if the image is already available + let result = self.shared.image_cache_task.get_image_if_available(url.clone()); + + match result { + Ok(image) => Some(image), + Err(state) => { + // If we are emitting an output file, then we need to block on + // image load or we risk emitting an output file missing the image. + let is_sync = opts::get().output_file.is_some(); + + match (state, is_sync) { + // Image failed to load, so just return nothing + (ImageState::LoadError, _) => None, + // Not loaded, test mode - load the image synchronously + (_, true) => { + let (sync_tx, sync_rx) = channel(); + self.shared.image_cache_task.request_image(url, + ImageCacheChan(sync_tx), + None); + sync_rx.recv().unwrap().image + } + // Not yet requested, async mode - request image from the cache + (ImageState::NotRequested, false) => { + self.shared.image_cache_task.request_image(url, + self.shared.image_cache_sender.clone(), + None); + None + } + // Image has been requested, is still pending. Return no image + // for this paint loop. When the image loads it will trigger + // a reflow and/or repaint. + (ImageState::Pending, false) => None, + } + } + } + } } diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 3e1af9c16b8..9677c72ecaa 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -20,7 +20,6 @@ use fragment::{ScannedTextFragmentInfo, SpecificFragmentInfo}; use inline::InlineFlow; use list_item::ListItemFlow; use model::{self, MaybeAuto, ToGfxMatrix}; -use opaque_node::OpaqueNodeMethods; use geom::{Matrix2D, Point2D, Rect, Size2D, SideOffsets2D}; use gfx::color; @@ -36,7 +35,6 @@ use png::{self, PixelsByColorType}; use msg::compositor_msg::ScrollPolicy; use msg::constellation_msg::Msg as ConstellationMsg; use msg::constellation_msg::ConstellationChan; -use net_traits::image::holder::ImageHolder; use util::cursor::Cursor; use util::geometry::{self, Au, ZERO_POINT, to_px, to_frac_px}; use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode}; @@ -398,95 +396,86 @@ impl FragmentDisplayListBuilding for Fragment { clip: &ClippingRegion, image_url: &Url) { let background = style.get_background(); - let mut holder = ImageHolder::new(image_url.clone(), - layout_context.shared.image_cache.clone()); - let image = match holder.get_image(self.node.to_untrusted_node_address()) { - None => { - // No image data at all? Do nothing. - // - // TODO: Add some kind of placeholder background image. - debug!("(building display list) no background image :("); - return - } - Some(image) => image, - }; - debug!("(building display list) building background image"); + let image = layout_context.get_or_request_image(image_url.clone()); + if let Some(image) = image { + debug!("(building display list) building background image"); - // Use `background-size` to get the size. - let mut bounds = *absolute_bounds; - let image_size = self.compute_background_image_size(style, &bounds, &*image); + // Use `background-size` to get the size. + let mut bounds = *absolute_bounds; + let image_size = self.compute_background_image_size(style, &bounds, &*image); - // Clip. - // - // TODO: Check the bounds to see if a clip item is actually required. - let clip = clip.clone().intersect_rect(&bounds); + // Clip. + // + // TODO: Check the bounds to see if a clip item is actually required. + let clip = clip.clone().intersect_rect(&bounds); - // Use `background-attachment` to get the initial virtual origin - let (virtual_origin_x, virtual_origin_y) = match background.background_attachment { - background_attachment::T::scroll => { - (absolute_bounds.origin.x, absolute_bounds.origin.y) - } - background_attachment::T::fixed => { - (Au(0), Au(0)) - } - }; + // Use `background-attachment` to get the initial virtual origin + let (virtual_origin_x, virtual_origin_y) = match background.background_attachment { + background_attachment::T::scroll => { + (absolute_bounds.origin.x, absolute_bounds.origin.y) + } + background_attachment::T::fixed => { + (Au(0), Au(0)) + } + }; - // Use `background-position` to get the offset. - let horizontal_position = model::specified(background.background_position.horizontal, - bounds.size.width - image_size.width); - let vertical_position = model::specified(background.background_position.vertical, - bounds.size.height - image_size.height); + // Use `background-position` to get the offset. + let horizontal_position = model::specified(background.background_position.horizontal, + bounds.size.width - image_size.width); + let vertical_position = model::specified(background.background_position.vertical, + bounds.size.height - image_size.height); - let abs_x = virtual_origin_x + horizontal_position; - let abs_y = virtual_origin_y + vertical_position; + let abs_x = virtual_origin_x + horizontal_position; + let abs_y = virtual_origin_y + vertical_position; - // Adjust origin and size based on background-repeat - match background.background_repeat { - background_repeat::T::no_repeat => { - bounds.origin.x = abs_x; - bounds.origin.y = abs_y; - bounds.size.width = image_size.width; - bounds.size.height = image_size.height; - } - background_repeat::T::repeat_x => { - bounds.origin.y = abs_y; - bounds.size.height = image_size.height; - ImageFragmentInfo::tile_image(&mut bounds.origin.x, - &mut bounds.size.width, - abs_x, - image_size.width.to_nearest_px() as u32); - } - background_repeat::T::repeat_y => { - bounds.origin.x = abs_x; - bounds.size.width = image_size.width; - ImageFragmentInfo::tile_image(&mut bounds.origin.y, - &mut bounds.size.height, - abs_y, - image_size.height.to_nearest_px() as u32); - } - background_repeat::T::repeat => { - ImageFragmentInfo::tile_image(&mut bounds.origin.x, - &mut bounds.size.width, - abs_x, - image_size.width.to_nearest_px() as u32); - ImageFragmentInfo::tile_image(&mut bounds.origin.y, - &mut bounds.size.height, - abs_y, - image_size.height.to_nearest_px() as u32); - } - }; + // Adjust origin and size based on background-repeat + match background.background_repeat { + background_repeat::T::no_repeat => { + bounds.origin.x = abs_x; + bounds.origin.y = abs_y; + bounds.size.width = image_size.width; + bounds.size.height = image_size.height; + } + background_repeat::T::repeat_x => { + bounds.origin.y = abs_y; + bounds.size.height = image_size.height; + ImageFragmentInfo::tile_image(&mut bounds.origin.x, + &mut bounds.size.width, + abs_x, + image_size.width.to_nearest_px() as u32); + } + background_repeat::T::repeat_y => { + bounds.origin.x = abs_x; + bounds.size.width = image_size.width; + ImageFragmentInfo::tile_image(&mut bounds.origin.y, + &mut bounds.size.height, + abs_y, + image_size.height.to_nearest_px() as u32); + } + background_repeat::T::repeat => { + ImageFragmentInfo::tile_image(&mut bounds.origin.x, + &mut bounds.size.width, + abs_x, + image_size.width.to_nearest_px() as u32); + ImageFragmentInfo::tile_image(&mut bounds.origin.y, + &mut bounds.size.height, + abs_y, + image_size.height.to_nearest_px() as u32); + } + }; - // Create the image display item. - display_list.push(DisplayItem::ImageClass(box ImageDisplayItem { - base: BaseDisplayItem::new(bounds, - DisplayItemMetadata::new(self.node, - style, - Cursor::DefaultCursor), - clip), - image: image.clone(), - stretch_size: Size2D(image_size.width, image_size.height), - image_rendering: style.get_effects().image_rendering.clone(), - }), level); + // Create the image display item. + display_list.push(DisplayItem::ImageClass(box ImageDisplayItem { + base: BaseDisplayItem::new(bounds, + DisplayItemMetadata::new(self.node, + style, + Cursor::DefaultCursor), + clip), + image: image.clone(), + stretch_size: Size2D(image_size.width, image_size.height), + image_rendering: style.get_effects().image_rendering.clone(), + }), level); + } } fn build_display_list_for_background_linear_gradient(&self, @@ -973,11 +962,8 @@ impl FragmentDisplayListBuilding for Fragment { } } SpecificFragmentInfo::Image(ref mut image_fragment) => { - let image_ref = &mut image_fragment.image; - if let Some(image) = image_ref.get_image(self.node.to_untrusted_node_address()) { - debug!("(building display list) building image fragment"); - - // Place the image into the display list. + // Place the image into the display list. + if let Some(ref image) = image_fragment.image { display_list.content.push_back(DisplayItem::ImageClass(box ImageDisplayItem { base: BaseDisplayItem::new(stacking_relative_content_box, DisplayItemMetadata::new(self.node, @@ -988,11 +974,6 @@ impl FragmentDisplayListBuilding for Fragment { stretch_size: stacking_relative_content_box.size, image_rendering: self.style.get_effects().image_rendering.clone(), })); - } else { - // No image data at all? Do nothing. - // - // TODO: Add some kind of placeholder image. - debug!("(building display list) no image :("); } } SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => { diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 4ddea7d62c8..168bcb2c83b 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -28,8 +28,7 @@ use gfx::display_list::{BLUR_INFLATION_FACTOR, OpaqueNode}; use gfx::text::glyph::CharIndex; use gfx::text::text_run::{TextRun, TextRunSlice}; use msg::constellation_msg::{ConstellationChan, Msg, PipelineId, SubpageId}; -use net_traits::image::holder::ImageHolder; -use net_traits::local_image_cache::LocalImageCache; +use net_traits::image::base::Image; use rustc_serialize::{Encodable, Encoder}; use script_traits::UntrustedNodeAddress; use std::borrow::ToOwned; @@ -297,7 +296,7 @@ impl CanvasFragmentInfo { pub struct ImageFragmentInfo { /// The image held within this fragment. pub replaced_image_fragment_info: ReplacedImageFragmentInfo, - pub image: ImageHolder, + pub image: Option>, } impl ImageFragmentInfo { @@ -306,8 +305,8 @@ impl ImageFragmentInfo { /// FIXME(pcwalton): The fact that image fragments store the cache in the fragment makes little /// sense to me. pub fn new(node: &ThreadSafeLayoutNode, - image_url: Url, - local_image_cache: Arc>>) + url: Option, + layout_context: &LayoutContext) -> ImageFragmentInfo { fn convert_length(node: &ThreadSafeLayoutNode, name: &Atom) -> Option { let element = node.as_element(); @@ -316,32 +315,42 @@ impl ImageFragmentInfo { .map(|pixels| Au::from_px(pixels)) } + let image = url.and_then(|url| layout_context.get_or_request_image(url)); + ImageFragmentInfo { replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node, convert_length(node, &atom!("width")), convert_length(node, &atom!("height"))), - image: ImageHolder::new(image_url, local_image_cache) + image: image, } } /// Returns the original inline-size of the image. pub fn image_inline_size(&mut self) -> Au { - let size = self.image.get_size(self.replaced_image_fragment_info.for_node).unwrap_or(Size2D::zero()); - Au::from_px(if self.replaced_image_fragment_info.writing_mode_is_vertical { - size.height - } else { - size.width - } as isize) + match self.image { + Some(ref image) => { + Au::from_px(if self.replaced_image_fragment_info.writing_mode_is_vertical { + image.height + } else { + image.width + } as isize) + } + None => Au(0) + } } /// Returns the original block-size of the image. pub fn image_block_size(&mut self) -> Au { - let size = self.image.get_size(self.replaced_image_fragment_info.for_node).unwrap_or(Size2D::zero()); - Au::from_px(if self.replaced_image_fragment_info.writing_mode_is_vertical { - size.width - } else { - size.height - } as isize) + match self.image { + Some(ref image) => { + Au::from_px(if self.replaced_image_fragment_info.writing_mode_is_vertical { + image.width + } else { + image.height + } as isize) + } + None => Au(0) + } } /// Tile an image diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs index 054b8f51dc9..97a401507f6 100644 --- a/components/layout/layout_task.rs +++ b/components/layout/layout_task.rs @@ -46,16 +46,15 @@ use profile::mem::{self, Report, ReportsChan}; use profile::time::{self, ProfilerMetadata, profile}; use profile::time::{TimerMetadataFrameType, TimerMetadataReflowType}; use net_traits::{load_bytes_iter, ResourceTask}; -use net_traits::image_cache_task::{ImageCacheTask, ImageResponseMsg}; -use net_traits::local_image_cache::{ImageResponder, LocalImageCache}; +use net_traits::image_cache_task::{ImageCacheTask, ImageCacheResult, ImageCacheChan}; use script::dom::bindings::js::LayoutJS; use script::dom::node::{LayoutData, Node}; use script::layout_interface::{Animation, ContentBoxResponse, ContentBoxesResponse}; use script::layout_interface::{HitTestResponse, LayoutChan, LayoutRPC}; use script::layout_interface::{MouseOverResponse, Msg, Reflow, ReflowGoal, ReflowQueryType}; use script::layout_interface::{ScriptLayoutChan, ScriptReflow, TrustedNodeAddress}; -use script_traits::{ConstellationControlMsg, CompositorEvent, OpaqueScriptLayoutChannel}; -use script_traits::{ScriptControlChan, UntrustedNodeAddress}; +use script_traits::{ConstellationControlMsg, OpaqueScriptLayoutChannel}; +use script_traits::ScriptControlChan; use std::borrow::ToOwned; use std::cell::Cell; use std::mem::transmute; @@ -74,7 +73,7 @@ use util::geometry::{Au, MAX_RECT}; use util::logical_geometry::LogicalPoint; use util::mem::HeapSizeOf; use util::opts; -use util::smallvec::{SmallVec, SmallVec1, VecLike}; +use util::smallvec::SmallVec; use util::task::spawn_named_with_send_on_failure; use util::task_state; use util::workqueue::WorkQueue; @@ -86,8 +85,8 @@ pub struct LayoutTaskData { /// The root of the flow tree. pub root_flow: Option, - /// The local image cache. - pub local_image_cache: Arc>>, + /// The image cache. + pub image_cache_task: ImageCacheTask, /// The channel on which messages can be sent to the constellation. pub constellation_chan: ConstellationChan, @@ -145,6 +144,12 @@ pub struct LayoutTask { /// The port on which we receive messages from the constellation pub pipeline_port: Receiver, + /// The port on which we receive messages from the image cache + image_cache_receiver: Receiver, + + /// The channel on which the image cache can send messages to ourself. + image_cache_sender: ImageCacheChan, + /// The channel on which we or others can send messages to ourselves. pub chan: LayoutChan, @@ -169,9 +174,6 @@ pub struct LayoutTask { /// The channel on which messages can be sent to the resource task. pub resource_task: ResourceTask, - /// The channel on which messages can be sent to the image cache. - pub image_cache_task: ImageCacheTask, - /// Public interface to the font cache task. pub font_cache_task: FontCacheTask, @@ -185,26 +187,6 @@ pub struct LayoutTask { pub rw_data: Arc>, } -struct LayoutImageResponder { - id: PipelineId, - script_chan: ScriptControlChan, -} - -impl ImageResponder for LayoutImageResponder { - fn respond(&self) -> Box { - let id = self.id.clone(); - let script_chan = self.script_chan.clone(); - box move |_, node_address| { - let ScriptControlChan(ref chan) = script_chan; - debug!("Dirtying {:p}", node_address.0); - let mut nodes = SmallVec1::new(); - nodes.vec_push(node_address); - drop(chan.send(ConstellationControlMsg::SendEvent( - id, CompositorEvent::ReflowEvent(nodes)))) - } - } -} - impl LayoutTaskFactory for LayoutTask { /// Spawns a new layout task. fn create(_phantom: Option<&mut LayoutTask>, @@ -218,7 +200,7 @@ impl LayoutTaskFactory for LayoutTask { script_chan: ScriptControlChan, paint_chan: PaintChan, resource_task: ResourceTask, - img_cache_task: ImageCacheTask, + image_cache_task: ImageCacheTask, font_cache_task: FontCacheTask, time_profiler_chan: time::ProfilerChan, memory_profiler_chan: mem::ProfilerChan, @@ -237,7 +219,7 @@ impl LayoutTaskFactory for LayoutTask { script_chan, paint_chan, resource_task, - img_cache_task, + image_cache_task, font_cache_task, time_profiler_chan, memory_profiler_chan); @@ -295,8 +277,6 @@ impl LayoutTask { time_profiler_chan: time::ProfilerChan, mem_profiler_chan: mem::ProfilerChan) -> LayoutTask { - let local_image_cache = - Arc::new(Mutex::new(LocalImageCache::new(image_cache_task.clone()))); let screen_size = Size2D(Au(0), Au(0)); let device = Device::new( MediaType::Screen, @@ -317,6 +297,7 @@ impl LayoutTask { // Create the channel on which new animations can be sent. let (new_animations_sender, new_animations_receiver) = channel(); + let (image_cache_sender, image_cache_receiver) = channel(); LayoutTask { id: id, @@ -332,13 +313,14 @@ impl LayoutTask { mem_profiler_chan: mem_profiler_chan, reporter_name: reporter_name, resource_task: resource_task, - image_cache_task: image_cache_task.clone(), font_cache_task: font_cache_task, first_reflow: Cell::new(true), + image_cache_receiver: image_cache_receiver, + image_cache_sender: ImageCacheChan(image_cache_sender), rw_data: Arc::new(Mutex::new( LayoutTaskData { root_flow: None, - local_image_cache: local_image_cache, + image_cache_task: image_cache_task, constellation_chan: constellation_chan, screen_size: screen_size, stacking_context: None, @@ -371,7 +353,8 @@ impl LayoutTask { url: &Url) -> SharedLayoutContext { SharedLayoutContext { - image_cache: rw_data.local_image_cache.clone(), + image_cache_task: rw_data.image_cache_task.clone(), + image_cache_sender: self.image_cache_sender.clone(), screen_size: rw_data.screen_size.clone(), screen_size_changed: screen_size_changed, constellation_chan: rw_data.constellation_chan.clone(), @@ -393,21 +376,26 @@ impl LayoutTask { enum PortToRead { Pipeline, Script, + ImageCache, } let port_to_read = { let sel = Select::new(); let mut port1 = sel.handle(&self.port); let mut port2 = sel.handle(&self.pipeline_port); + let mut port3 = sel.handle(&self.image_cache_receiver); unsafe { port1.add(); port2.add(); + port3.add(); } let ret = sel.wait(); if ret == port1.id() { PortToRead::Script } else if ret == port2.id() { PortToRead::Pipeline + } else if ret == port3.id() { + PortToRead::ImageCache } else { panic!("invalid select result"); } @@ -424,11 +412,15 @@ impl LayoutTask { possibly_locked_rw_data) } } - }, + } PortToRead::Script => { let msg = self.port.recv().unwrap(); self.handle_request_helper(msg, possibly_locked_rw_data) } + PortToRead::ImageCache => { + let _ = self.image_cache_receiver.recv().unwrap(); + self.repaint(possibly_locked_rw_data) + } } } @@ -458,6 +450,33 @@ impl LayoutTask { } } + /// Repaint the scene, without performing style matching. This is typically + /// used when an image arrives asynchronously and triggers a relayout and + /// repaint. + /// TODO: In the future we could detect if the image size hasn't changed + /// since last time and avoid performing a complete layout pass. + fn repaint<'a>(&'a self, + possibly_locked_rw_data: &mut Option>) -> bool { + let mut rw_data = self.lock_rw_data(possibly_locked_rw_data); + + let reflow_info = Reflow { + goal: ReflowGoal::ForDisplay, + page_clip_rect: MAX_RECT, + }; + + let mut layout_context = self.build_shared_layout_context(&*rw_data, + false, + None, + &self.url); + + self.perform_post_style_recalc_layout_passes(&reflow_info, + &mut *rw_data, + &mut layout_context); + + + true + } + /// Receives and dispatches messages from other tasks. fn handle_request_helper<'a>(&'a self, request: Msg, @@ -823,12 +842,6 @@ impl LayoutTask { let mut rw_data = self.lock_rw_data(possibly_locked_rw_data); - { - // Reset the image cache. - let mut local_image_cache = rw_data.local_image_cache.lock().unwrap(); - local_image_cache.next_round(self.make_on_image_available_cb()); - } - // TODO: Calculate the "actual viewport": // http://www.w3.org/TR/css-device-adapt/#actual-viewport let viewport_size = data.window_size.initial_viewport; @@ -1039,24 +1052,6 @@ impl LayoutTask { } } - /// When images can't be loaded in time to display they trigger - /// this callback in some task somewhere. This will send a message - /// to the script task, and ultimately cause the image to be - /// re-requested. We probably don't need to go all the way back to - /// the script task for this. - /// - /// FIXME(pcwalton): Rewrite all of this. - fn make_on_image_available_cb(&self) -> Box+Send> { - // This has a crazy signature because the image cache needs to - // make multiple copies of the callback, and the dom event - // channel is not a copyable type, so this is actually a - // little factory to produce callbacks - box LayoutImageResponder { - id: self.id.clone(), - script_chan: self.script_chan.clone(), - } as Box+Send> - } - /// Handles a message to destroy layout data. Layout data must be destroyed on *this* task /// because the struct type is transmuted to a different type on the script side. unsafe fn handle_reap_layout_data(&self, layout_data: LayoutData) { diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index d1e92547bb9..000d2794626 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -116,7 +116,7 @@ pub trait TLayoutNode { fn image_url(&self) -> Option { unsafe { match HTMLImageElementCast::to_layout_js(self.get_jsmanaged()) { - Some(elem) => elem.image().as_ref().map(|url| (*url).clone()), + Some(elem) => elem.image_url().as_ref().map(|url| (*url).clone()), None => panic!("not an image!") } } diff --git a/components/layout_traits/lib.rs b/components/layout_traits/lib.rs index af1c4e03cd4..8381b64c3ef 100644 --- a/components/layout_traits/lib.rs +++ b/components/layout_traits/lib.rs @@ -50,7 +50,7 @@ pub trait LayoutTaskFactory { script_chan: ScriptControlChan, paint_chan: PaintChan, resource_task: ResourceTask, - img_cache_task: ImageCacheTask, + image_cache_task: ImageCacheTask, font_cache_task: FontCacheTask, time_profiler_chan: time::ProfilerChan, mem_profiler_chan: mem::ProfilerChan, diff --git a/components/net/image_cache_task.rs b/components/net/image_cache_task.rs index b231f69ec39..54949d53b54 100644 --- a/components/net/image_cache_task.rs +++ b/components/net/image_cache_task.rs @@ -2,408 +2,361 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use net_traits::ResourceTask; +use collections::borrow::ToOwned; use net_traits::image::base::{Image, load_from_memory}; -use net_traits::image_cache_task::{ImageResponseMsg, ImageCacheTask, Msg}; -use net_traits::image_cache_task::{load_image_data}; -use profile::time::{self, profile}; -use url::Url; - -use std::borrow::ToOwned; +use net_traits::image_cache_task::{ImageState, ImageCacheTask, ImageCacheChan, ImageCacheCommand, ImageCacheResult}; +use net_traits::load_whole_resource; use std::collections::HashMap; use std::collections::hash_map::Entry::{Occupied, Vacant}; -use std::mem::replace; -use std::sync::{Arc, Mutex}; -use std::sync::mpsc::{channel, Receiver, Sender}; +use std::mem; +use std::sync::Arc; +use std::sync::mpsc::{channel, Sender, Receiver, Select}; use util::resource_files::resources_dir_path; use util::task::spawn_named; use util::taskpool::TaskPool; +use url::Url; +use net_traits::{AsyncResponseTarget, ControlMsg, LoadData, ResponseAction, ResourceTask, LoadConsumer}; +use net_traits::image_cache_task::ImageResponder; -pub trait ImageCacheTaskFactory { - fn new(resource_task: ResourceTask, task_pool: TaskPool, - time_profiler_chan: time::ProfilerChan, - load_placeholder: LoadPlaceholder) -> Self; - fn new_sync(resource_task: ResourceTask, task_pool: TaskPool, - time_profiler_chan: time::ProfilerChan, - load_placeholder: LoadPlaceholder) -> Self; +/// +/// TODO(gw): Remaining work on image cache: +/// * Make use of the prefetch support in various parts of the code. +/// * Experiment with changing the image 'key' from being a url to a resource id +/// This might be a decent performance win and/or memory saving in some cases (esp. data urls) +/// * Profile time in GetImageIfAvailable - might be worth caching these results per paint / layout task. +/// + +/// Represents an image that is either being loaded +/// by the resource task, or decoded by a worker thread. +struct PendingLoad { + bytes: Vec, + result: Option>, + listeners: Vec, } -impl ImageCacheTaskFactory for ImageCacheTask { - fn new(resource_task: ResourceTask, task_pool: TaskPool, - time_profiler_chan: time::ProfilerChan, - load_placeholder: LoadPlaceholder) -> ImageCacheTask { - let (chan, port) = channel(); - let chan_clone = chan.clone(); - - spawn_named("ImageCacheTask".to_owned(), move || { - let mut cache = ImageCache { - resource_task: resource_task, - port: port, - chan: chan_clone, - state_map: HashMap::new(), - wait_map: HashMap::new(), - need_exit: None, - task_pool: task_pool, - time_profiler_chan: time_profiler_chan, - placeholder_data: Arc::new(vec!()), - }; - cache.run(load_placeholder); - }); - - ImageCacheTask { - chan: chan, +impl PendingLoad { + fn new() -> PendingLoad { + PendingLoad { + bytes: vec!(), + result: None, + listeners: vec!(), } } - fn new_sync(resource_task: ResourceTask, task_pool: TaskPool, - time_profiler_chan: time::ProfilerChan, - load_placeholder: LoadPlaceholder) -> ImageCacheTask { - let (chan, port) = channel(); + fn add_listener(&mut self, listener: ImageListener) { + self.listeners.push(listener); + } +} - spawn_named("ImageCacheTask (sync)".to_owned(), move || { - let inner_cache: ImageCacheTask = ImageCacheTaskFactory::new(resource_task, task_pool, - time_profiler_chan, load_placeholder); +/// Represents an image that has completed loading. +/// Images that fail to load (due to network or decode +/// failure) are still stored here, so that they aren't +/// fetched again. +struct CompletedLoad { + image: Option>, +} - loop { - let msg: Msg = port.recv().unwrap(); - - match msg { - Msg::GetImage(url, response) => { - inner_cache.send(Msg::WaitForImage(url, response)); - } - Msg::Exit(response) => { - inner_cache.send(Msg::Exit(response)); - break; - } - msg => inner_cache.send(msg) - } - } - }); - - ImageCacheTask { - chan: chan, +impl CompletedLoad { + fn new(image: Option>) -> CompletedLoad { + CompletedLoad { + image: image, } } } +/// Stores information to notify a client when the state +/// of an image changes. +struct ImageListener { + sender: ImageCacheChan, + responder: Option>, +} + +impl ImageListener { + fn new(sender: ImageCacheChan, responder: Option>) -> ImageListener { + ImageListener { + sender: sender, + responder: responder, + } + } + + fn notify(self, image: Option>) { + let ImageCacheChan(ref sender) = self.sender; + let msg = ImageCacheResult { + responder: self.responder, + image: image, + }; + sender.send(msg).ok(); + } +} + +struct ResourceLoadInfo { + action: ResponseAction, + url: Url, +} + +struct ResourceListener { + url: Url, + sender: Sender, +} + +impl AsyncResponseTarget for ResourceListener { + fn invoke_with_listener(&self, action: ResponseAction) { + self.sender.send(ResourceLoadInfo { + action: action, + url: self.url.clone(), + }).unwrap(); + } +} + +/// Implementation of the image cache struct ImageCache { - /// A handle to the resource task for fetching the image binaries - resource_task: ResourceTask, - /// The port on which we'll receive client requests - port: Receiver, - /// A copy of the shared chan to give to child tasks - chan: Sender, - /// The state of processing an image for a URL - state_map: HashMap, - /// List of clients waiting on a WaitForImage response - wait_map: HashMap>>>>, - need_exit: Option>, + // Receive commands from clients + cmd_receiver: Receiver, + + // Receive notifications from the resource task + progress_receiver: Receiver, + progress_sender: Sender, + + // Receive notifications from the decoder thread pool + decoder_receiver: Receiver, + decoder_sender: Sender, + + // Worker threads for decoding images. task_pool: TaskPool, - time_profiler_chan: time::ProfilerChan, - // Default image used when loading fails. - placeholder_data: Arc>, + + // Resource task handle + resource_task: ResourceTask, + + // Images that are loading over network, or decoding. + pending_loads: HashMap, + + // Images that have finished loading (successful or not) + completed_loads: HashMap, + + // The placeholder image used when an image fails to load + placeholder_image: Option>, } -#[derive(Clone)] -enum ImageState { - Init, - Prefetching(AfterPrefetch), - Prefetched(Vec), - Decoding, - Decoded(Arc), - Failed +/// Message that the decoder worker threads send to main image cache task. +struct DecoderMsg { + url: Url, + image: Option, } -#[derive(Clone)] -enum AfterPrefetch { - DoDecode, - DoNotDecode -} - -pub enum LoadPlaceholder { - Preload, - Ignore +/// The types of messages that the main image cache task receives. +enum SelectResult { + Command(ImageCacheCommand), + Progress(ResourceLoadInfo), + Decoder(DecoderMsg), } impl ImageCache { - // Used to preload the default placeholder. - fn init(&mut self) { - let mut placeholder_url = resources_dir_path(); - placeholder_url.push("rippy.jpg"); - let image = load_image_data(Url::from_file_path(&*placeholder_url).unwrap(), self.resource_task.clone(), &self.placeholder_data); - - match image { - Err(..) => debug!("image_cache_task: failed loading the placeholder."), - Ok(image_data) => self.placeholder_data = Arc::new(image_data), - } - } - - pub fn run(&mut self, load_placeholder: LoadPlaceholder) { - // We have to load the placeholder before running. - match load_placeholder { - LoadPlaceholder::Preload => self.init(), - LoadPlaceholder::Ignore => debug!("image_cache_task: use old behavior."), - } - - let mut store_chan: Option> = None; - let mut store_prefetched_chan: Option> = None; + fn run(&mut self) { + let mut exit_sender: Option> = None; loop { - let msg = self.port.recv().unwrap(); + let result = { + let sel = Select::new(); - match msg { - Msg::Prefetch(url) => self.prefetch(url), - Msg::StorePrefetchedImageData(url, data) => { - store_prefetched_chan.map(|chan| { - chan.send(()).unwrap(); - }); - store_prefetched_chan = None; + let mut cmd_handle = sel.handle(&self.cmd_receiver); + let mut progress_handle = sel.handle(&self.progress_receiver); + let mut decoder_handle = sel.handle(&self.decoder_receiver); - self.store_prefetched_image_data(url, data); - } - Msg::Decode(url) => self.decode(url), - Msg::StoreImage(url, image) => { - store_chan.map(|chan| { - chan.send(()).unwrap(); - }); - store_chan = None; - - self.store_image(url, image) - } - Msg::GetImage(url, response) => self.get_image(url, response), - Msg::WaitForImage(url, response) => { - self.wait_for_image(url, response) - } - Msg::WaitForStore(chan) => store_chan = Some(chan), - Msg::WaitForStorePrefetched(chan) => store_prefetched_chan = Some(chan), - Msg::Exit(response) => { - assert!(self.need_exit.is_none()); - self.need_exit = Some(response); - } - } - - let need_exit = replace(&mut self.need_exit, None); - - match need_exit { - Some(response) => { - // Wait until we have no outstanding requests and subtasks - // before exiting - let mut can_exit = true; - for (_, state) in self.state_map.iter() { - match *state { - ImageState::Prefetching(..) => can_exit = false, - ImageState::Decoding => can_exit = false, - - ImageState::Init | ImageState::Prefetched(..) | - ImageState::Decoded(..) | ImageState::Failed => () - } + unsafe { + cmd_handle.add(); + progress_handle.add(); + decoder_handle.add(); } - if can_exit { - response.send(()).unwrap(); - break; + let ret = sel.wait(); + + if ret == cmd_handle.id() { + SelectResult::Command(self.cmd_receiver.recv().unwrap()) + } else if ret == decoder_handle.id() { + SelectResult::Decoder(self.decoder_receiver.recv().unwrap()) } else { - self.need_exit = Some(response); + SelectResult::Progress(self.progress_receiver.recv().unwrap()) } - } - None => () - } - } - } + }; - fn get_state(&self, url: &Url) -> ImageState { - match self.state_map.get(url) { - Some(state) => state.clone(), - None => ImageState::Init - } - } - - fn set_state(&mut self, url: Url, state: ImageState) { - self.state_map.insert(url, state); - } - - fn prefetch(&mut self, url: Url) { - match self.get_state(&url) { - ImageState::Init => { - let to_cache = self.chan.clone(); - let resource_task = self.resource_task.clone(); - let url_clone = url.clone(); - let placeholder = self.placeholder_data.clone(); - spawn_named("ImageCacheTask (prefetch)".to_owned(), move || { - let url = url_clone; - debug!("image_cache_task: started fetch for {}", url.serialize()); - - let image = load_image_data(url.clone(), resource_task.clone(), &placeholder); - to_cache.send(Msg::StorePrefetchedImageData(url.clone(), image)).unwrap(); - debug!("image_cache_task: ended fetch for {}", url.serialize()); - }); - - self.set_state(url, ImageState::Prefetching(AfterPrefetch::DoNotDecode)); - } - - ImageState::Prefetching(..) | ImageState::Prefetched(..) | - ImageState::Decoding | ImageState::Decoded(..) | ImageState::Failed => { - // We've already begun working on this image - } - } - } - - fn store_prefetched_image_data(&mut self, url: Url, data: Result, ()>) { - match self.get_state(&url) { - ImageState::Prefetching(next_step) => { - match data { - Ok(data) => { - self.set_state(url.clone(), ImageState::Prefetched(data)); - match next_step { - AfterPrefetch::DoDecode => self.decode(url), - _ => () + match result { + SelectResult::Command(cmd) => { + exit_sender = self.handle_cmd(cmd); } - } - Err(..) => { - self.set_state(url.clone(), ImageState::Failed); - self.purge_waiters(url, || ImageResponseMsg::ImageFailed); - } - } - } - - ImageState::Init - | ImageState::Prefetched(..) - | ImageState::Decoding - | ImageState::Decoded(..) - | ImageState::Failed => { - panic!("wrong state for storing prefetched image") - } - } - } - - fn decode(&mut self, url: Url) { - match self.get_state(&url) { - ImageState::Init => panic!("decoding image before prefetch"), - - ImageState::Prefetching(AfterPrefetch::DoNotDecode) => { - // We don't have the data yet, queue up the decode - self.set_state(url, ImageState::Prefetching(AfterPrefetch::DoDecode)) - } - - ImageState::Prefetching(AfterPrefetch::DoDecode) => { - // We don't have the data yet, but the decode request is queued up - } - - ImageState::Prefetched(data) => { - let to_cache = self.chan.clone(); - let url_clone = url.clone(); - let time_profiler_chan = self.time_profiler_chan.clone(); - - self.task_pool.execute(move || { - let url = url_clone; - debug!("image_cache_task: started image decode for {}", url.serialize()); - let image = profile(time::ProfilerCategory::ImageDecoding, - None, time_profiler_chan, || { - load_from_memory(&data) - }); - - let image = image.map(Arc::new); - to_cache.send(Msg::StoreImage(url.clone(), image)).unwrap(); - debug!("image_cache_task: ended image decode for {}", url.serialize()); - }); - - self.set_state(url, ImageState::Decoding); - } - - ImageState::Decoding | ImageState::Decoded(..) | ImageState::Failed => { - // We've already begun decoding - } - } - } - - fn store_image(&mut self, url: Url, image: Option>) { - - match self.get_state(&url) { - ImageState::Decoding => { - match image { - Some(image) => { - self.set_state(url.clone(), ImageState::Decoded(image.clone())); - self.purge_waiters(url, || ImageResponseMsg::ImageReady(image.clone()) ); - } - None => { - self.set_state(url.clone(), ImageState::Failed); - self.purge_waiters(url, || ImageResponseMsg::ImageFailed ); - } - } - } - - ImageState::Init - | ImageState::Prefetching(..) - | ImageState::Prefetched(..) - | ImageState::Decoded(..) - | ImageState::Failed => { - panic!("incorrect state in store_image") - } - } - } - - fn purge_waiters(&mut self, url: Url, f: F) where F: Fn() -> ImageResponseMsg { - match self.wait_map.remove(&url) { - Some(waiters) => { - let items = waiters.lock().unwrap(); - for response in items.iter() { - response.send(f()).unwrap(); + SelectResult::Progress(msg) => { + self.handle_progress(msg); + } + SelectResult::Decoder(msg) => { + self.handle_decoder(msg); + } + } + + // Can only exit when all pending loads are complete. + if let Some(ref exit_sender) = exit_sender { + if self.pending_loads.len() == 0 { + exit_sender.send(()).unwrap(); + break; } } - None => () } } - fn get_image(&self, url: Url, response: Sender) { - match self.get_state(&url) { - ImageState::Init => panic!("request for image before prefetch"), - ImageState::Prefetching(AfterPrefetch::DoDecode) => response.send(ImageResponseMsg::ImageNotReady).unwrap(), - ImageState::Prefetching(AfterPrefetch::DoNotDecode) | ImageState::Prefetched(..) => panic!("request for image before decode"), - ImageState::Decoding => response.send(ImageResponseMsg::ImageNotReady).unwrap(), - ImageState::Decoded(image) => response.send(ImageResponseMsg::ImageReady(image)).unwrap(), - ImageState::Failed => response.send(ImageResponseMsg::ImageFailed).unwrap(), - } - } - - fn wait_for_image(&mut self, url: Url, response: Sender) { - match self.get_state(&url) { - ImageState::Init => panic!("request for image before prefetch"), - - ImageState::Prefetching(AfterPrefetch::DoNotDecode) | ImageState::Prefetched(..) => panic!("request for image before decode"), - - ImageState::Prefetching(AfterPrefetch::DoDecode) | ImageState::Decoding => { - // We don't have this image yet - match self.wait_map.entry(url) { - Occupied(mut entry) => { - entry.get_mut().lock().unwrap().push(response); + // Handle a request from a client + fn handle_cmd(&mut self, cmd: ImageCacheCommand) -> Option> { + match cmd { + ImageCacheCommand::Exit(sender) => { + return Some(sender); + } + ImageCacheCommand::RequestImage(url, result_chan, responder) => { + self.request_image(url, result_chan, responder); + } + ImageCacheCommand::GetImageIfAvailable(url, consumer) => { + let result = match self.completed_loads.get(&url) { + Some(completed_load) => { + completed_load.image.clone().ok_or(ImageState::LoadError) } - Vacant(entry) => { - entry.insert(Arc::new(Mutex::new(vec!(response)))); + None => { + let pending_load = self.pending_loads.get(&url); + Err(pending_load.map_or(ImageState::NotRequested, |_| ImageState::Pending)) + } + }; + consumer.send(result).unwrap(); + } + }; + + None + } + + // Handle progress messages from the resource task + fn handle_progress(&mut self, msg: ResourceLoadInfo) { + match msg.action { + ResponseAction::HeadersAvailable(_) => {} + ResponseAction::DataAvailable(data) => { + let pending_load = self.pending_loads.get_mut(&msg.url).unwrap(); + pending_load.bytes.push_all(data.as_slice()); + } + ResponseAction::ResponseComplete(result) => { + match result { + Ok(()) => { + let pending_load = self.pending_loads.get_mut(&msg.url).unwrap(); + pending_load.result = Some(result); + + let bytes = mem::replace(&mut pending_load.bytes, vec!()); + let url = msg.url.clone(); + let sender = self.decoder_sender.clone(); + + self.task_pool.execute(move || { + let image = load_from_memory(bytes.as_slice()); + let msg = DecoderMsg { + url: url, + image: image + }; + sender.send(msg).unwrap(); + }); + } + Err(_) => { + let placeholder_image = self.placeholder_image.clone(); + self.complete_load(msg.url, placeholder_image); } } } + } + } - ImageState::Decoded(image) => { - response.send(ImageResponseMsg::ImageReady(image)).unwrap(); + // Handle a message from one of the decoder worker threads + fn handle_decoder(&mut self, msg: DecoderMsg) { + let image = msg.image.map(Arc::new); + self.complete_load(msg.url, image); + } + + // Change state of a url from pending -> loaded. + fn complete_load(&mut self, url: Url, image: Option>) { + let pending_load = self.pending_loads.remove(&url).unwrap(); + + let completed_load = CompletedLoad::new(image.clone()); + self.completed_loads.insert(url, completed_load); + + for listener in pending_load.listeners.into_iter() { + listener.notify(image.clone()); + } + } + + // Request an image from the cache + fn request_image(&mut self, url: Url, result_chan: ImageCacheChan, responder: Option>) { + let image_listener = ImageListener::new(result_chan, responder); + + // Check if already completed + match self.completed_loads.get(&url) { + Some(completed_load) => { + // It's already completed, return a notify straight away + image_listener.notify(completed_load.image.clone()); } + None => { + // Check if the load is already pending + match self.pending_loads.entry(url.clone()) { + Occupied(mut e) => { + // It's pending, so add the listener for state changes + let pending_load = e.get_mut(); + pending_load.add_listener(image_listener); + } + Vacant(e) => { + // A new load request! Add the pending load and request + // it from the resource task. + let mut pending_load = PendingLoad::new(); + pending_load.add_listener(image_listener); + e.insert(pending_load); - ImageState::Failed => { - response.send(ImageResponseMsg::ImageFailed).unwrap(); + let load_data = LoadData::new(url.clone()); + let listener = box ResourceListener { + url: url, + sender: self.progress_sender.clone(), + }; + self.resource_task.send(ControlMsg::Load(load_data, LoadConsumer::Listener(listener))).unwrap(); + } + } } } } } -pub fn spawn_listener(f: F) -> Sender - where F: FnOnce(Receiver) + Send + 'static, - A: Send + 'static -{ - let (setup_chan, setup_port) = channel(); +/// Create a new image cache. +pub fn new_image_cache_task(resource_task: ResourceTask) -> ImageCacheTask { + let (cmd_sender, cmd_receiver) = channel(); + let (progress_sender, progress_receiver) = channel(); + let (decoder_sender, decoder_receiver) = channel(); - spawn_named("ImageCacheTask (listener)".to_owned(), move || { - let (chan, port) = channel(); - setup_chan.send(chan).unwrap(); - f(port); + spawn_named("ImageCacheThread".to_owned(), move || { + + // Preload the placeholder image, used when images fail to load. + let mut placeholder_url = resources_dir_path(); + // TODO (Savago): replace for a prettier one. + placeholder_url.push("rippy.jpg"); + let url = Url::from_file_path(&*placeholder_url).unwrap(); + let placeholder_image = match load_whole_resource(&resource_task, url) { + Err(..) => { + debug!("image_cache_task: failed loading the placeholder."); + None + } + Ok((_, image_data)) => { + Some(Arc::new(load_from_memory(&image_data).unwrap())) + } + }; + + let mut cache = ImageCache { + cmd_receiver: cmd_receiver, + progress_sender: progress_sender, + progress_receiver: progress_receiver, + decoder_sender: decoder_sender, + decoder_receiver: decoder_receiver, + task_pool: TaskPool::new(4), + pending_loads: HashMap::new(), + completed_loads: HashMap::new(), + resource_task: resource_task, + placeholder_image: placeholder_image, + }; + + cache.run(); }); - setup_port.recv().unwrap() + + ImageCacheTask::new(cmd_sender) } diff --git a/components/net_traits/image/holder.rs b/components/net_traits/image/holder.rs deleted file mode 100644 index 6e79694f1dc..00000000000 --- a/components/net_traits/image/holder.rs +++ /dev/null @@ -1,100 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use image::base::Image; -use image_cache_task::ImageResponseMsg; -use local_image_cache::LocalImageCache; - -use geom::size::Size2D; -use std::sync::{Arc, Mutex}; -use url::Url; - -// FIXME: Nasty coupling here This will be a problem if we want to factor out image handling from -// the network stack. This should probably be factored out into an interface and use dependency -// injection. - -/// A struct to store image data. The image will be loaded once the first time it is requested, -/// and an Arc will be stored. Clones of this Arc are given out on demand. -#[derive(Clone)] -pub struct ImageHolder { - url: Url, - image: Option>, - cached_size: Size2D, - local_image_cache: Arc>>, -} - -impl ImageHolder { - pub fn new(url: Url, local_image_cache: Arc>>) - -> ImageHolder { - debug!("ImageHolder::new() {}", url.serialize()); - let holder = ImageHolder { - url: url, - image: None, - cached_size: Size2D(0,0), - local_image_cache: local_image_cache.clone(), - }; - - // Tell the image cache we're going to be interested in this url - // FIXME: These two messages must be sent to prep an image for use - // but they are intended to be spread out in time. Ideally prefetch - // should be done as early as possible and decode only once we - // are sure that the image will be used. - { - let val = holder.local_image_cache.lock().unwrap(); - let mut local_image_cache = val; - local_image_cache.prefetch(&holder.url); - local_image_cache.decode(&holder.url); - } - - holder - } - - /// This version doesn't perform any computation, but may be stale w.r.t. newly-available image - /// data that determines size. - /// - /// The intent is that the impure version is used during layout when dimensions are used for - /// computing layout. - pub fn size(&self) -> Size2D { - self.cached_size - } - - /// Query and update the current image size. - pub fn get_size(&mut self, node_address: NodeAddress) -> Option> { - debug!("get_size() {}", self.url.serialize()); - self.get_image(node_address).map(|img| { - self.cached_size = Size2D(img.width, img.height); - self.cached_size.clone() - }) - } - - pub fn get_image_if_present(&self) -> Option> { - debug!("get_image_if_present() {}", self.url.serialize()); - self.image.clone() - } - - pub fn get_image(&mut self, node_address: NodeAddress) -> Option> { - debug!("get_image() {}", self.url.serialize()); - - // If this is the first time we've called this function, load - // the image and store it for the future - if self.image.is_none() { - let port = { - let val = self.local_image_cache.lock().unwrap(); - let mut local_image_cache = val; - local_image_cache.get_image(node_address, &self.url) - }; - match port.recv().unwrap() { - ImageResponseMsg::ImageReady(image) => self.image = Some(image), - ImageResponseMsg::ImageNotReady => debug!("image not ready for {}", self.url.serialize()), - ImageResponseMsg::ImageFailed => debug!("image decoding failed for {}", self.url.serialize()), - } - } - - return self.image.clone(); - } - - pub fn url(&self) -> &Url { - &self.url - } -} diff --git a/components/net_traits/image_cache_task.rs b/components/net_traits/image_cache_task.rs index 905a7de3611..29a89be1594 100644 --- a/components/net_traits/image_cache_task.rs +++ b/components/net_traits/image_cache_task.rs @@ -3,117 +3,92 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use image::base::Image; -use LoadConsumer::Channel; -use {ControlMsg, LoadData, ProgressMsg, ResourceTask}; use url::Url; - use std::sync::Arc; use std::sync::mpsc::{channel, Sender}; -pub enum Msg { - /// Tell the cache that we may need a particular image soon. Must be posted - /// before Decode - Prefetch(Url), +/// This is optionally passed to the image cache when requesting +/// and image, and returned to the specified event loop when the +/// image load completes. It is typically used to trigger a reflow +/// and/or repaint. +pub trait ImageResponder : Send { + fn respond(&self, Option>); +} - /// Tell the cache to decode an image. Must be posted before GetImage/WaitForImage - Decode(Url), +/// The current state of an image in the cache. +#[derive(PartialEq, Copy)] +pub enum ImageState { + Pending, + LoadError, + NotRequested, +} - /// Request an Image object for a URL. If the image is not is not immediately - /// available then ImageNotReady is returned. - GetImage(Url, Sender), +/// Channel for sending commands to the image cache. +#[derive(Clone)] +pub struct ImageCacheChan(pub Sender); - /// Wait for an image to become available (or fail to load). - WaitForImage(Url, Sender), +/// The result of an image cache command that is returned to the +/// caller. +pub struct ImageCacheResult { + pub responder: Option>, + pub image: Option>, +} + +/// Commands that the image cache understands. +pub enum ImageCacheCommand { + /// Request an image asynchronously from the cache. Supply a channel + /// to receive the result, and optionally an image responder + /// that is passed to the result channel. + RequestImage(Url, ImageCacheChan, Option>), + + /// Synchronously check the state of an image in the cache. + /// TODO(gw): Profile this on some real world sites and see + /// if it's worth caching the results of this locally in each + /// layout / paint task. + GetImageIfAvailable(Url, Sender, ImageState>>), /// Clients must wait for a response before shutting down the ResourceTask Exit(Sender<()>), - - /// Used by the prefetch tasks to post back image binaries - StorePrefetchedImageData(Url, Result, ()>), - - /// Used by the decoder tasks to post decoded images back to the cache - StoreImage(Url, Option>), - - /// For testing - WaitForStore(Sender<()>), - - /// For testing - WaitForStorePrefetched(Sender<()>), -} - -#[derive(Clone)] -pub enum ImageResponseMsg { - ImageReady(Arc), - ImageNotReady, - ImageFailed -} - -impl PartialEq for ImageResponseMsg { - fn eq(&self, other: &ImageResponseMsg) -> bool { - match (self, other) { - (&ImageResponseMsg::ImageReady(..), &ImageResponseMsg::ImageReady(..)) => panic!("unimplemented comparison"), - (&ImageResponseMsg::ImageNotReady, &ImageResponseMsg::ImageNotReady) => true, - (&ImageResponseMsg::ImageFailed, &ImageResponseMsg::ImageFailed) => true, - - (&ImageResponseMsg::ImageReady(..), _) | (&ImageResponseMsg::ImageNotReady, _) | (&ImageResponseMsg::ImageFailed, _) => false - } - } } +/// The client side of the image cache task. This can be safely cloned +/// and passed to different tasks. #[derive(Clone)] pub struct ImageCacheTask { - pub chan: Sender, + chan: Sender, } +/// The public API for the image cache task. impl ImageCacheTask { - pub fn send(&self, msg: Msg) { + + /// Construct a new image cache + pub fn new(chan: Sender) -> ImageCacheTask { + ImageCacheTask { + chan: chan, + } + } + + /// Asynchronously request and image. See ImageCacheCommand::RequestImage. + pub fn request_image(&self, + url: Url, + result_chan: ImageCacheChan, + responder: Option>) { + let msg = ImageCacheCommand::RequestImage(url, result_chan, responder); self.chan.send(msg).unwrap(); } -} -pub trait ImageCacheTaskClient { - fn exit(&self); -} + /// Get the current state of an image. See ImageCacheCommand::GetImageIfAvailable. + pub fn get_image_if_available(&self, url: Url) -> Result, ImageState> { + let (sender, receiver) = channel(); + let msg = ImageCacheCommand::GetImageIfAvailable(url, sender); + self.chan.send(msg).unwrap(); + receiver.recv().unwrap() + } -impl ImageCacheTaskClient for ImageCacheTask { - fn exit(&self) { + /// Shutdown the image cache task. + pub fn exit(&self) { let (response_chan, response_port) = channel(); - self.send(Msg::Exit(response_chan)); + self.chan.send(ImageCacheCommand::Exit(response_chan)).unwrap(); response_port.recv().unwrap(); } } - -pub fn load_image_data(url: Url, resource_task: ResourceTask, placeholder: &[u8]) -> Result, ()> { - let (response_chan, response_port) = channel(); - resource_task.send(ControlMsg::Load(LoadData::new(url.clone()), Channel(response_chan))).unwrap(); - - let mut image_data = vec!(); - - let progress_port = response_port.recv().unwrap().progress_port; - loop { - match progress_port.recv().unwrap() { - ProgressMsg::Payload(data) => { - image_data.push_all(&data); - } - ProgressMsg::Done(Ok(..)) => { - return Ok(image_data); - } - ProgressMsg::Done(Err(..)) => { - // Failure to load the requested image will return the - // placeholder instead. In case it failed to load at init(), - // we still recover and return Err() but nothing will be drawn. - if placeholder.len() != 0 { - debug!("image_cache_task: failed to load {:?}, use placeholder instead.", url); - // Clean in case there was an error after started loading the image. - image_data.clear(); - image_data.push_all(&placeholder); - return Ok(image_data); - } else { - debug!("image_cache_task: invalid placeholder."); - return Err(()); - } - } - } - } -} - diff --git a/components/net_traits/lib.rs b/components/net_traits/lib.rs index d73e3563194..1e7f4c328ca 100644 --- a/components/net_traits/lib.rs +++ b/components/net_traits/lib.rs @@ -6,7 +6,6 @@ #![feature(collections)] #![feature(core)] #![feature(rustc_private)] -#![feature(std_misc)] extern crate geom; extern crate hyper; @@ -28,7 +27,6 @@ use std::borrow::IntoCow; use std::sync::mpsc::{channel, Receiver, Sender}; pub mod image_cache_task; -pub mod local_image_cache; pub mod storage_task; /// Image handling. @@ -38,7 +36,6 @@ pub mod storage_task; /// caching is involved) and as a result it must live in here. pub mod image { pub mod base; - pub mod holder; } #[derive(Clone)] diff --git a/components/net_traits/local_image_cache.rs b/components/net_traits/local_image_cache.rs deleted file mode 100644 index 5a427562f6c..00000000000 --- a/components/net_traits/local_image_cache.rs +++ /dev/null @@ -1,170 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/*! -An adapter for ImageCacheTask that does local caching to avoid -extra message traffic, it also avoids waiting on the same image -multiple times and thus triggering reflows multiple times. -*/ - -use image_cache_task::{ImageResponseMsg, ImageCacheTask, Msg}; -use url::Url; - -use std::borrow::ToOwned; -use std::collections::HashMap; -use std::collections::hash_map::Entry::{Occupied, Vacant}; -use std::sync::mpsc::{channel, Receiver}; -use util::task::spawn_named; - -pub trait ImageResponder { - fn respond(&self) -> Box; -} - -pub struct LocalImageCache { - image_cache_task: ImageCacheTask, - round_number: u32, - on_image_available: Option+Send>>, - state_map: HashMap -} - -impl LocalImageCache { - pub fn new(image_cache_task: ImageCacheTask) -> LocalImageCache { - LocalImageCache { - image_cache_task: image_cache_task, - round_number: 1, - on_image_available: None, - state_map: HashMap::new() - } - } -} - -#[derive(Clone)] -struct ImageState { - prefetched: bool, - decoded: bool, - last_request_round: u32, - last_response: ImageResponseMsg -} - -impl LocalImageCache { - /// The local cache will only do a single remote request for a given - /// URL in each 'round'. Layout should call this each time it begins - pub fn next_round(&mut self, on_image_available: Box + Send>) { - self.round_number += 1; - self.on_image_available = Some(on_image_available); - } - - pub fn prefetch(&mut self, url: &Url) { - { - let state = self.get_state(url); - if state.prefetched { - return - } - - state.prefetched = true; - } - - self.image_cache_task.send(Msg::Prefetch((*url).clone())); - } - - pub fn decode(&mut self, url: &Url) { - { - let state = self.get_state(url); - if state.decoded { - return - } - state.decoded = true; - } - - self.image_cache_task.send(Msg::Decode((*url).clone())); - } - - // FIXME: Should return a Future - pub fn get_image(&mut self, node_address: NodeAddress, url: &Url) -> Receiver { - { - let round_number = self.round_number; - let state = self.get_state(url); - - // Save the previous round number for comparison - let last_round = state.last_request_round; - // Set the current round number for this image - state.last_request_round = round_number; - - match state.last_response { - ImageResponseMsg::ImageReady(ref image) => { - let (chan, port) = channel(); - chan.send(ImageResponseMsg::ImageReady(image.clone())).unwrap(); - return port; - } - ImageResponseMsg::ImageNotReady => { - if last_round == round_number { - let (chan, port) = channel(); - chan.send(ImageResponseMsg::ImageNotReady).unwrap(); - return port; - } else { - // We haven't requested the image from the - // remote cache this round - } - } - ImageResponseMsg::ImageFailed => { - let (chan, port) = channel(); - chan.send(ImageResponseMsg::ImageFailed).unwrap(); - return port; - } - } - } - - let (response_chan, response_port) = channel(); - self.image_cache_task.send(Msg::GetImage((*url).clone(), response_chan)); - - let response = response_port.recv().unwrap(); - match response { - ImageResponseMsg::ImageNotReady => { - // Need to reflow when the image is available - // FIXME: Instead we should be just passing a Future - // to the caller, then to the display list. Finally, - // the compositor should be responsible for waiting - // on the image to load and triggering layout - let image_cache_task = self.image_cache_task.clone(); - assert!(self.on_image_available.is_some()); - let on_image_available = - self.on_image_available.as_ref().unwrap().respond(); - let url = (*url).clone(); - spawn_named("LocalImageCache".to_owned(), move || { - let (response_chan, response_port) = channel(); - image_cache_task.send(Msg::WaitForImage(url, response_chan)); - on_image_available(response_port.recv().unwrap(), node_address); - }); - } - _ => () - } - - // Put a copy of the response in the cache - let response_copy = match response { - ImageResponseMsg::ImageReady(ref image) => ImageResponseMsg::ImageReady(image.clone()), - ImageResponseMsg::ImageNotReady => ImageResponseMsg::ImageNotReady, - ImageResponseMsg::ImageFailed => ImageResponseMsg::ImageFailed - }; - self.get_state(url).last_response = response_copy; - - let (chan, port) = channel(); - chan.send(response).unwrap(); - return port; - } - - fn get_state<'a>(&'a mut self, url: &Url) -> &'a mut ImageState { - match self.state_map.entry((*url).clone()) { - Occupied(entry) => entry.into_mut(), - Vacant(entry) => - entry.insert(ImageState { - prefetched: false, - decoded: false, - last_request_round: 0, - last_response: ImageResponseMsg::ImageNotReady, - }) - } - } -} - - diff --git a/components/script/dom/bindings/refcounted.rs b/components/script/dom/bindings/refcounted.rs index c009687e40a..8a626ac6b67 100644 --- a/components/script/dom/bindings/refcounted.rs +++ b/components/script/dom/bindings/refcounted.rs @@ -117,8 +117,11 @@ impl Drop for Trusted { assert!(*refcount > 0); *refcount -= 1; if *refcount == 0 { - self.script_chan.send( - ScriptMsg::RefcountCleanup(TrustedReference(self.ptr))).unwrap(); + // It's possible this send will fail if the script task + // has already exited. There's not much we can do at this + // point though. + let msg = ScriptMsg::RefcountCleanup(TrustedReference(self.ptr)); + let _ = self.script_chan.send(msg); } } } diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 0d261092bb4..d3de04ca57b 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -49,12 +49,13 @@ use js::rust::{Cx, Runtime}; use layout_interface::{LayoutRPC, LayoutChan}; use libc; use msg::constellation_msg::{PipelineId, SubpageId, WindowSizeData, WorkerId}; -use net_traits::image_cache_task::ImageCacheTask; +use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask}; use net_traits::storage_task::StorageType; use script_traits::ScriptControlChan; use script_traits::UntrustedNodeAddress; use msg::compositor_msg::ScriptListener; use msg::constellation_msg::ConstellationChan; +use net_traits::image::base::Image; use util::smallvec::{SmallVec1, SmallVec}; use util::str::{LengthOrPercentageOrAuto}; use std::cell::{Cell, RefCell}; @@ -66,6 +67,7 @@ use std::intrinsics::return_address; use std::old_io::timer::Timer; use std::ops::{Deref, DerefMut}; use std::rc::Rc; +use std::sync::Arc; use std::sync::mpsc::{Receiver, Sender}; use string_cache::{Atom, Namespace}; use style::properties::PropertyDeclarationBlock; @@ -248,7 +250,8 @@ no_jsmanaged_fields!(isize, i8, i16, i32, i64); no_jsmanaged_fields!(Sender); no_jsmanaged_fields!(Receiver); no_jsmanaged_fields!(Rect); -no_jsmanaged_fields!(ImageCacheTask, ScriptControlChan); +no_jsmanaged_fields!(Arc); +no_jsmanaged_fields!(Image, ImageCacheChan, ImageCacheTask, ScriptControlChan); no_jsmanaged_fields!(Atom, Namespace, Timer); no_jsmanaged_fields!(Trusted); no_jsmanaged_fields!(PropertyDeclarationBlock); diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index f6111739d8b..022b31dd055 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -33,7 +33,7 @@ use canvas::canvas_paint_task::{LinearGradientStyle, RadialGradientStyle}; use canvas::canvas_paint_task::{LineCapStyle, LineJoinStyle, CompositionOrBlending}; use net_traits::image::base::Image; -use net_traits::image_cache_task::{ImageResponseMsg, Msg}; +use net_traits::image_cache_task::ImageCacheChan; use png::PixelsByColorType; use std::borrow::ToOwned; @@ -275,16 +275,11 @@ impl CanvasRenderingContext2D { let canvas = self.canvas.root(); let window = window_from_node(canvas.r()).root(); let window = window.r(); - let image_cache_task = window.image_cache_task().clone(); - image_cache_task.send(Msg::Prefetch(url.clone())); - image_cache_task.send(Msg::Decode(url.clone())); + let image_cache = window.image_cache_task(); let (response_chan, response_port) = channel(); - image_cache_task.send(Msg::WaitForImage(url, response_chan)); - match response_port.recv().unwrap() { - ImageResponseMsg::ImageReady(image) => Some(image), - ImageResponseMsg::ImageFailed => None, - _ => panic!("Image Cache: Unknown Result") - } + image_cache.request_image(url, ImageCacheChan(response_chan), None); + let result = response_port.recv().unwrap(); + result.image } fn create_drawable_rect(&self, x: f64, y: f64, w: f64, h: f64) -> Option> { diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index f93d525f1fc..4ddf91cb8bd 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -7,30 +7,36 @@ use dom::attr::{AttrHelpers, AttrValue}; use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::HTMLImageElementBinding; use dom::bindings::codegen::Bindings::HTMLImageElementBinding::HTMLImageElementMethods; -use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast, HTMLElementCast, HTMLImageElementDerived}; +use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast, EventTargetCast, HTMLElementCast, HTMLImageElementDerived}; +use dom::bindings::global::GlobalRef; use dom::bindings::js::{JSRef, LayoutJS, Temporary}; +use dom::bindings::refcounted::Trusted; use dom::document::{Document, DocumentHelpers}; use dom::element::Element; use dom::element::AttributeHandlers; use dom::eventtarget::{EventTarget, EventTargetTypeId}; use dom::element::ElementTypeId; +use dom::event::{Event, EventBubbles, EventCancelable, EventHelpers}; use dom::htmlelement::{HTMLElement, HTMLElementTypeId}; -use dom::node::{Node, NodeTypeId, NodeHelpers, NodeDamage, window_from_node}; +use dom::node::{document_from_node, Node, NodeTypeId, NodeHelpers, NodeDamage, window_from_node}; use dom::virtualmethods::VirtualMethods; use dom::window::WindowHelpers; -use net_traits::image_cache_task; use util::geometry::to_px; use util::str::DOMString; use string_cache::Atom; +use net_traits::image::base::Image; +use net_traits::image_cache_task::ImageResponder; use url::{Url, UrlParser}; use std::borrow::ToOwned; +use std::sync::Arc; #[dom_struct] pub struct HTMLImageElement { htmlelement: HTMLElement, - image: DOMRefCell>, + url: DOMRefCell>, + image: DOMRefCell>>, } impl HTMLImageElementDerived for EventTarget { @@ -45,7 +51,7 @@ pub trait HTMLImageElementHelpers { impl<'a> HTMLImageElementHelpers for JSRef<'a, HTMLImageElement> { fn get_url(&self) -> Option{ - self.image.borrow().clone() + self.url.borrow().clone() } } @@ -53,6 +59,48 @@ trait PrivateHTMLImageElementHelpers { fn update_image(self, value: Option<(DOMString, &Url)>); } +/// This is passed to the image cache when the src attribute +/// changes. It is returned via a message to the script task, +/// which marks the element as dirty and triggers a reflow. +struct Responder { + element: Trusted, +} + +impl Responder { + fn new(element: Trusted) -> Responder { + Responder { + element: element + } + } +} + +impl ImageResponder for Responder { + fn respond(&self, image: Option>) { + // Update the image field + let element = self.element.to_temporary().root(); + let element_ref = element.r(); + *element_ref.image.borrow_mut() = image; + + // Mark the node dirty + let node = NodeCast::from_ref(element.r()); + let document = document_from_node(node).root(); + document.r().content_changed(node, NodeDamage::OtherNodeDamage); + + // Fire image.onload + let window = window_from_node(document.r()).root(); + let event = Event::new(GlobalRef::Window(window.r()), + "load".to_owned(), + EventBubbles::DoesNotBubble, + EventCancelable::NotCancelable).root(); + let event = event.r(); + let target: JSRef = EventTargetCast::from_ref(node); + event.fire(target); + + // Trigger reflow + window.r().add_pending_reflow(); + } +} + impl<'a> PrivateHTMLImageElementHelpers for JSRef<'a, HTMLImageElement> { /// Makes the local `image` member match the status of the `src` attribute and starts /// prefetching the image. This method must be called after `src` is changed. @@ -64,17 +112,18 @@ impl<'a> PrivateHTMLImageElementHelpers for JSRef<'a, HTMLImageElement> { let image_cache = window.image_cache_task(); match value { None => { + *self.url.borrow_mut() = None; *self.image.borrow_mut() = None; } Some((src, base_url)) => { let img_url = UrlParser::new().base_url(base_url).parse(src.as_slice()); // FIXME: handle URL parse errors more gracefully. let img_url = img_url.unwrap(); - *self.image.borrow_mut() = Some(img_url.clone()); + *self.url.borrow_mut() = Some(img_url.clone()); - // inform the image cache to load this, but don't store a - // handle. - image_cache.send(image_cache_task::Msg::Prefetch(img_url)); + let trusted_node = Trusted::new(window.get_cx(), self, window.script_chan()); + let responder = box Responder::new(trusted_node); + image_cache.request_image(img_url, window.image_cache_chan(), Some(responder)); } } } @@ -84,6 +133,7 @@ impl HTMLImageElement { fn new_inherited(localName: DOMString, prefix: Option, document: JSRef) -> HTMLImageElement { HTMLImageElement { htmlelement: HTMLElement::new_inherited(HTMLElementTypeId::HTMLImageElement, localName, prefix, document), + url: DOMRefCell::new(None), image: DOMRefCell::new(None), } } @@ -97,14 +147,22 @@ impl HTMLImageElement { pub trait LayoutHTMLImageElementHelpers { #[allow(unsafe_code)] - unsafe fn image(&self) -> Option; + unsafe fn image(&self) -> Option>; + + #[allow(unsafe_code)] + unsafe fn image_url(&self) -> Option; } impl LayoutHTMLImageElementHelpers for LayoutJS { #[allow(unsafe_code)] - unsafe fn image(&self) -> Option { + unsafe fn image(&self) -> Option> { (*self.unsafe_get()).image.borrow_for_layout().clone() } + + #[allow(unsafe_code)] + unsafe fn image_url(&self) -> Option { + (*self.unsafe_get()).url.borrow_for_layout().clone() + } } impl<'a> HTMLImageElementMethods for JSRef<'a, HTMLImageElement> { @@ -163,6 +221,29 @@ impl<'a> HTMLImageElementMethods for JSRef<'a, HTMLImageElement> { elem.set_uint_attribute(&atom!("height"), height) } + fn NaturalWidth(self) -> u32 { + let image = self.image.borrow(); + + match *image { + Some(ref image) => image.width, + None => 0, + } + } + + fn NaturalHeight(self) -> u32 { + let image = self.image.borrow(); + + match *image { + Some(ref image) => image.height, + None => 0, + } + } + + fn Complete(self) -> bool { + let image = self.image.borrow(); + image.is_some() + } + make_getter!(Name); make_setter!(SetName, "name"); diff --git a/components/script/dom/htmlobjectelement.rs b/components/script/dom/htmlobjectelement.rs index 6b82c63ea82..a6d46a21c11 100644 --- a/components/script/dom/htmlobjectelement.rs +++ b/components/script/dom/htmlobjectelement.rs @@ -4,6 +4,7 @@ use dom::attr::Attr; use dom::attr::AttrHelpers; +use dom::bindings::cell::DOMRefCell; use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods; use dom::bindings::codegen::Bindings::HTMLObjectElementBinding; use dom::bindings::codegen::Bindings::HTMLObjectElementBinding::HTMLObjectElementMethods; @@ -20,15 +21,15 @@ use dom::node::{Node, NodeTypeId, NodeHelpers, window_from_node}; use dom::validitystate::ValidityState; use dom::virtualmethods::VirtualMethods; -use net_traits::image_cache_task::{self, ImageCacheTask}; +use net_traits::image::base::Image; use util::str::DOMString; +use std::sync::Arc; use string_cache::Atom; -use url::Url; - #[dom_struct] pub struct HTMLObjectElement { htmlelement: HTMLElement, + image: DOMRefCell>>, } impl HTMLObjectElementDerived for EventTarget { @@ -41,6 +42,7 @@ impl HTMLObjectElement { fn new_inherited(localName: DOMString, prefix: Option, document: JSRef) -> HTMLObjectElement { HTMLObjectElement { htmlelement: HTMLElement::new_inherited(HTMLElementTypeId::HTMLObjectElement, localName, prefix, document), + image: DOMRefCell::new(None), } } @@ -52,24 +54,20 @@ impl HTMLObjectElement { } trait ProcessDataURL { - fn process_data_url(&self, image_cache: ImageCacheTask); + fn process_data_url(&self); } impl<'a> ProcessDataURL for JSRef<'a, HTMLObjectElement> { // Makes the local `data` member match the status of the `data` attribute and starts /// prefetching the image. This method must be called after `data` is changed. - fn process_data_url(&self, image_cache: ImageCacheTask) { + fn process_data_url(&self) { let elem: JSRef = ElementCast::from_ref(*self); // TODO: support other values match (elem.get_attribute(&ns!(""), &atom!("type")).map(|x| x.root().r().Value()), elem.get_attribute(&ns!(""), &atom!("data")).map(|x| x.root().r().Value())) { - (None, Some(uri)) => { - if is_image_data(uri.as_slice()) { - let data_url = Url::parse(uri.as_slice()).unwrap(); - // Issue #84 - image_cache.send(image_cache_task::Msg::Prefetch(data_url)); - } + (None, Some(_uri)) => { + // TODO(gw): Prefetch the image here. } _ => { } } @@ -107,8 +105,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLObjectElement> { match attr.local_name() { &atom!("data") => { - let window = window_from_node(*self).root(); - self.process_data_url(window.r().image_cache_task().clone()); + self.process_data_url(); }, _ => () } diff --git a/components/script/dom/webidls/HTMLImageElement.webidl b/components/script/dom/webidls/HTMLImageElement.webidl index ab9b4ce72a1..71b49229393 100644 --- a/components/script/dom/webidls/HTMLImageElement.webidl +++ b/components/script/dom/webidls/HTMLImageElement.webidl @@ -14,9 +14,9 @@ interface HTMLImageElement : HTMLElement { attribute boolean isMap; attribute unsigned long width; attribute unsigned long height; - //readonly attribute unsigned long naturalWidth; - //readonly attribute unsigned long naturalHeight; - //readonly attribute boolean complete; + readonly attribute unsigned long naturalWidth; + readonly attribute unsigned long naturalHeight; + readonly attribute boolean complete; // also has obsolete members }; diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index b46a5af952d..6a2aa52be32 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -38,7 +38,7 @@ use devtools_traits::{DevtoolsControlChan, TimelineMarker, TimelineMarkerType, T use msg::compositor_msg::ScriptListener; use msg::constellation_msg::{LoadData, PipelineId, SubpageId, ConstellationChan, WindowSizeData, WorkerId}; use net_traits::ResourceTask; -use net_traits::image_cache_task::ImageCacheTask; +use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask}; use net_traits::storage_task::{StorageTask, StorageType}; use util::geometry::{self, Au, MAX_RECT}; use util::opts; @@ -67,18 +67,19 @@ use std::sync::mpsc::TryRecvError::{Empty, Disconnected}; use time; /// Extra information concerning the reason for reflowing. +#[derive(Debug)] pub enum ReflowReason { CachedPageNeededReflow, FirstLoad, KeyEvent, MouseEvent, Query, - ReceivedReflowEvent, Timer, Viewport, WindowResize, DOMContentLoaded, DocumentLoaded, + ImageLoaded, } #[dom_struct] @@ -89,6 +90,7 @@ pub struct Window { console: MutNullableJS, navigator: MutNullableJS, image_cache_task: ImageCacheTask, + image_cache_chan: ImageCacheChan, compositor: DOMRefCell>, browser_context: DOMRefCell>, page: Rc, @@ -160,6 +162,9 @@ pub struct Window { /// An enlarged rectangle around the page contents visible in the viewport, used /// to prevent creating display list items for content that is far away from the viewport. page_clip_rect: Cell>, + + /// A counter of the number of pending reflows for this window. + pending_reflow_count: Cell, } impl Window { @@ -179,6 +184,10 @@ impl Window { self.script_chan.clone() } + pub fn image_cache_chan(&self) -> ImageCacheChan { + self.image_cache_chan.clone() + } + pub fn get_next_worker_id(&self) -> WorkerId { let worker_id = self.next_worker_id.get(); let WorkerId(id_num) = worker_id; @@ -481,6 +490,8 @@ pub trait WindowHelpers { fn windowproxy_handler(self) -> WindowProxyHandler; fn get_next_subpage_id(self) -> SubpageId; fn layout_is_idle(self) -> bool; + fn get_pending_reflow_count(self) -> u32; + fn add_pending_reflow(self); fn set_resize_event(self, event: WindowSizeData); fn steal_resize_event(self) -> Option; fn set_page_clip_rect_with_new_viewport(self, viewport: Rect) -> bool; @@ -549,11 +560,9 @@ impl<'a> WindowHelpers for JSRef<'a, Window> { None => return, }; - debug!("script: performing reflow for goal {:?}", goal); - let root: JSRef = NodeCast::from_ref(root); if query_type == ReflowQueryType::NoQuery && !root.get_has_dirty_descendants() { - debug!("root has no dirty descendants; avoiding reflow"); + debug!("root has no dirty descendants; avoiding reflow (reason {:?})", reason); return } @@ -562,6 +571,8 @@ impl<'a> WindowHelpers for JSRef<'a, Window> { None => return, }; + debug!("script: performing reflow for goal {:?} reason {:?}", goal, reason); + if self.need_emit_timeline_marker(TimelineMarkerType::Reflow) { let marker = TimelineMarker::new("Reflow".to_owned(), TracingMetadata::IntervalStart); self.emit_timeline_marker(marker); @@ -604,6 +615,8 @@ impl<'a> WindowHelpers for JSRef<'a, Window> { self.join_layout(); + self.pending_reflow_count.set(0); + if self.need_emit_timeline_marker(TimelineMarkerType::Reflow) { let marker = TimelineMarker::new("Reflow".to_owned(), TracingMetadata::IntervalEnd); self.emit_timeline_marker(marker); @@ -745,6 +758,14 @@ impl<'a> WindowHelpers for JSRef<'a, Window> { port.is_none() } + fn get_pending_reflow_count(self) -> u32 { + self.pending_reflow_count.get() + } + + fn add_pending_reflow(self) { + self.pending_reflow_count.set(self.pending_reflow_count.get() + 1); + } + fn set_resize_event(self, event: WindowSizeData) { self.resize_event.set(Some(event)); } @@ -828,6 +849,7 @@ impl Window { pub fn new(js_context: Rc, page: Rc, script_chan: Box, + image_cache_chan: ImageCacheChan, control_chan: ScriptControlChan, compositor: Box, image_cache_task: ImageCacheTask, @@ -850,6 +872,7 @@ impl Window { let win = box Window { eventtarget: EventTarget::new_inherited(EventTargetTypeId::Window), script_chan: script_chan, + image_cache_chan: image_cache_chan, control_chan: control_chan, console: Default::default(), compositor: DOMRefCell::new(compositor), @@ -882,6 +905,7 @@ impl Window { layout_rpc: layout_rpc, layout_join_port: DOMRefCell::new(None), window_size: Cell::new(window_size), + pending_reflow_count: Cell::new(0), devtools_marker_sender: RefCell::new(None), devtools_markers: RefCell::new(HashSet::new()), @@ -929,12 +953,12 @@ fn debug_reflow_events(goal: &ReflowGoal, query_type: &ReflowQueryType, reason: ReflowReason::KeyEvent => "\tKeyEvent", ReflowReason::MouseEvent => "\tMouseEvent", ReflowReason::Query => "\tQuery", - ReflowReason::ReceivedReflowEvent => "\tReceivedReflowEvent", ReflowReason::Timer => "\tTimer", ReflowReason::Viewport => "\tViewport", ReflowReason::WindowResize => "\tWindowResize", ReflowReason::DOMContentLoaded => "\tDOMContentLoaded", ReflowReason::DocumentLoaded => "\tDocumentLoaded", + ReflowReason::ImageLoaded => "\tImageLoaded", }); println!("{}", debug_msg); diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 14638ddcd82..e10e3e9e583 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -36,7 +36,7 @@ use dom::event::{Event, EventHelpers, EventBubbles, EventCancelable}; use dom::htmliframeelement::{HTMLIFrameElement, HTMLIFrameElementHelpers}; use dom::uievent::UIEvent; use dom::eventtarget::EventTarget; -use dom::node::{self, Node, NodeHelpers, NodeDamage, window_from_node}; +use dom::node::{Node, NodeHelpers, NodeDamage, window_from_node}; use dom::window::{Window, WindowHelpers, ScriptHelpers, ReflowReason}; use dom::worker::TrustedWorkerAddress; use parse::html::{HTMLInput, parse_html}; @@ -50,7 +50,7 @@ use devtools_traits::{DevtoolsControlChan, DevtoolsControlPort, DevtoolsPageInfo use devtools_traits::{DevtoolsControlMsg, DevtoolScriptControlMsg}; use devtools_traits::{TimelineMarker, TimelineMarkerType, TracingMetadata}; use script_traits::CompositorEvent; -use script_traits::CompositorEvent::{ResizeEvent, ReflowEvent, ClickEvent}; +use script_traits::CompositorEvent::{ResizeEvent, ClickEvent}; use script_traits::CompositorEvent::{MouseDownEvent, MouseUpEvent}; use script_traits::CompositorEvent::{MouseMoveEvent, KeyEvent}; use script_traits::{NewLayoutInfo, OpaqueScriptLayoutChannel}; @@ -64,7 +64,7 @@ use msg::constellation_msg::{Failure, WindowSizeData, PipelineExitType}; use msg::constellation_msg::Msg as ConstellationMsg; use net_traits::{ResourceTask, ControlMsg, LoadResponse, LoadConsumer}; use net_traits::LoadData as NetLoadData; -use net_traits::image_cache_task::ImageCacheTask; +use net_traits::image_cache_task::{ImageCacheChan, ImageCacheTask, ImageCacheResult}; use net_traits::storage_task::StorageTask; use string_cache::Atom; use util::geometry::to_frac_px; @@ -296,6 +296,12 @@ pub struct ScriptTask { /// A handle to the compositor for communicating ready state messages. compositor: DOMRefCell>, + /// The port on which we receive messages from the image cache + image_cache_port: Receiver, + + /// The channel on which the image cache can send messages to ourself. + image_cache_channel: ImageCacheChan, + /// For providing instructions to an optional devtools server. devtools_chan: Option, /// For receiving commands from an optional devtools server. Will be ignored if @@ -437,7 +443,7 @@ impl ScriptTask { constellation_chan: ConstellationChan, resource_task: ResourceTask, storage_task: StorageTask, - img_cache_task: ImageCacheTask, + image_cache_task: ImageCacheTask, devtools_chan: Option) -> ScriptTask { let runtime = ScriptTask::new_rt_and_cx(); @@ -463,11 +469,16 @@ impl ScriptTask { } let (devtools_sender, devtools_receiver) = channel(); + let (image_cache_channel, image_cache_port) = channel(); + ScriptTask { page: DOMRefCell::new(None), incomplete_loads: DOMRefCell::new(vec!()), - image_cache_task: img_cache_task, + image_cache_task: image_cache_task, + image_cache_channel: ImageCacheChan(image_cache_channel), + image_cache_port: image_cache_port, + resource_task: resource_task, storage_task: storage_task, @@ -558,6 +569,7 @@ impl ScriptTask { FromConstellation(ConstellationControlMsg), FromScript(ScriptMsg), FromDevtools(DevtoolScriptControlMsg), + FromImageCache(ImageCacheResult), } // Store new resizes, and gather all other events. @@ -569,12 +581,14 @@ impl ScriptTask { let mut port1 = sel.handle(&self.port); let mut port2 = sel.handle(&self.control_port); let mut port3 = sel.handle(&self.devtools_port); + let mut port4 = sel.handle(&self.image_cache_port); unsafe { port1.add(); port2.add(); if self.devtools_chan.is_some() { port3.add(); } + port4.add(); } let ret = sel.wait(); if ret == port1.id() { @@ -583,6 +597,8 @@ impl ScriptTask { MixedMessage::FromConstellation(self.control_port.recv().unwrap()) } else if ret == port3.id() { MixedMessage::FromDevtools(self.devtools_port.recv().unwrap()) + } else if ret == port4.id() { + MixedMessage::FromImageCache(self.image_cache_port.recv().unwrap()) } else { panic!("unexpected select result") } @@ -629,7 +645,10 @@ impl ScriptTask { match self.control_port.try_recv() { Err(_) => match self.port.try_recv() { Err(_) => match self.devtools_port.try_recv() { - Err(_) => break, + Err(_) => match self.image_cache_port.try_recv() { + Err(_) => break, + Ok(ev) => event = MixedMessage::FromImageCache(ev), + }, Ok(ev) => event = MixedMessage::FromDevtools(ev), }, Ok(ev) => event = MixedMessage::FromScript(ev), @@ -649,6 +668,23 @@ impl ScriptTask { MixedMessage::FromConstellation(inner_msg) => self.handle_msg_from_constellation(inner_msg), MixedMessage::FromScript(inner_msg) => self.handle_msg_from_script(inner_msg), MixedMessage::FromDevtools(inner_msg) => self.handle_msg_from_devtools(inner_msg), + MixedMessage::FromImageCache(inner_msg) => self.handle_msg_from_image_cache(inner_msg), + } + } + + // Issue batched reflows on any pages that require it (e.g. if images loaded) + // TODO(gw): In the future we could probably batch other types of reflows + // into this loop too, but for now it's only images. + let page = self.page.borrow(); + if let Some(page) = page.as_ref() { + for page in page.iter() { + let window = page.window().root(); + let pending_reflows = window.r().get_pending_reflow_count(); + if pending_reflows > 0 { + window.r().reflow(ReflowGoal::ForDisplay, + ReflowQueryType::NoQuery, + ReflowReason::ImageLoaded); + } } } @@ -743,6 +779,10 @@ impl ScriptTask { } } + fn handle_msg_from_image_cache(&self, msg: ImageCacheResult) { + msg.responder.unwrap().respond(msg.image); + } + fn handle_resize(&self, id: PipelineId, size: WindowSizeData) { let page = self.page.borrow(); if let Some(ref page) = page.as_ref() { @@ -1061,6 +1101,7 @@ impl ScriptTask { let window = Window::new(self.js_runtime.cx.clone(), page.clone(), self.chan.clone(), + self.image_cache_channel.clone(), self.control_chan.clone(), self.compositor.borrow_mut().dup(), self.image_cache_task.clone(), @@ -1207,29 +1248,6 @@ impl ScriptTask { self.handle_resize_event(pipeline_id, new_size); } - ReflowEvent(nodes) => { - // FIXME(pcwalton): This event seems to only be used by the image cache task, and - // the interaction between it and the image holder is really racy. I think that, in - // order to fix this race, we need to rewrite the image cache task to make the - // image holder responsible for the lifecycle of image loading instead of having - // the image holder and layout task both be observers. Then we can have the DOM - // image element observe the state of the image holder and have it send reflows - // via the normal dirtying mechanism, and ultimately remove this event. - // - // See the implementation of `Width()` and `Height()` in `HTMLImageElement` for - // fallout of this problem. - for node in nodes.iter() { - let node_to_dirty = node::from_untrusted_node_address(self.js_runtime.rt(), - *node).root(); - let page = get_page(&self.root_page(), pipeline_id); - let document = page.document().root(); - document.r().content_changed(node_to_dirty.r(), - NodeDamage::OtherNodeDamage); - } - - self.handle_reflow_event(pipeline_id); - } - ClickEvent(button, point) => { let _marker; if self.need_emit_timeline_marker(TimelineMarkerType::DOMEvent) { @@ -1332,16 +1350,6 @@ impl ScriptTask { event.fire(wintarget); } - fn handle_reflow_event(&self, pipeline_id: PipelineId) { - debug!("script got reflow event"); - let page = get_page(&self.root_page(), pipeline_id); - let document = page.document().root(); - let window = window_from_node(document.r()).root(); - window.r().reflow(ReflowGoal::ForDisplay, - ReflowQueryType::NoQuery, - ReflowReason::ReceivedReflowEvent); - } - /// Initiate a non-blocking fetch for a specified resource. Stores the InProgressLoad /// argument until a notification is received that the fetch is complete. fn start_page_load(&self, incomplete: InProgressLoad, mut load_data: LoadData) { diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index a21a6ae3d1f..b5045d5a832 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -24,7 +24,6 @@ use msg::compositor_msg::ScriptListener; use net_traits::ResourceTask; use net_traits::image_cache_task::ImageCacheTask; use net_traits::storage_task::StorageTask; -use util::smallvec::SmallVec1; use std::any::Any; use std::sync::mpsc::{Sender, Receiver}; @@ -89,7 +88,6 @@ pub enum MouseButton { /// Events from the compositor that the script task needs to know about pub enum CompositorEvent { ResizeEvent(WindowSizeData), - ReflowEvent(SmallVec1), ClickEvent(MouseButton, Point2D), MouseDownEvent(MouseButton, Point2D), MouseUpEvent(MouseButton, Point2D), diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 1be279d5528..22ec02646ef 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -46,17 +46,15 @@ use msg::constellation_msg::ConstellationChan; use script::dom::bindings::codegen::RegisterBindings; -use net::image_cache_task::{ImageCacheTaskFactory, LoadPlaceholder}; +use net::image_cache_task::new_image_cache_task; use net::storage_task::StorageTaskFactory; use net::resource_task::new_resource_task; -use net_traits::image_cache_task::ImageCacheTask; use net_traits::storage_task::StorageTask; use gfx::font_cache_task::FontCacheTask; use profile::mem; use profile::time; use util::opts; -use util::taskpool::TaskPool; use std::rc::Rc; use std::sync::mpsc::Sender; @@ -88,10 +86,6 @@ impl Browser { // bindings to implement JS proxies. RegisterBindings::RegisterProxyHandlers(); - // Use this thread pool to load-balance simple tasks, such as - // image decoding. - let shared_task_pool = TaskPool::new(8); - // Get both endpoints of a special channel for communication between // the client window and the compositor. This channel is unique because // messages to client may need to pump a platform-specific event loop @@ -111,8 +105,7 @@ impl Browser { compositor_proxy.clone_compositor_proxy(), time_profiler_chan.clone(), devtools_chan, - mem_profiler_chan.clone(), - shared_task_pool); + mem_profiler_chan.clone()); if let Some(port) = opts.webdriver_port { webdriver_server::start_server(port, constellation_chan.clone()); @@ -156,24 +149,13 @@ fn create_constellation(opts: opts::Opts, compositor_proxy: Box, time_profiler_chan: time::ProfilerChan, devtools_chan: Option>, - mem_profiler_chan: mem::ProfilerChan, - shared_task_pool: TaskPool) -> ConstellationChan { + mem_profiler_chan: mem::ProfilerChan) -> ConstellationChan { use std::env; // Create a Servo instance. let resource_task = new_resource_task(opts.user_agent.clone()); - // If we are emitting an output file, then we need to block on - // image load or we risk emitting an output file missing the - // image. - let image_cache_task: ImageCacheTask = if opts.output_file.is_some() { - ImageCacheTaskFactory::new_sync(resource_task.clone(), shared_task_pool, - time_profiler_chan.clone(), LoadPlaceholder::Preload) - } else { - ImageCacheTaskFactory::new(resource_task.clone(), shared_task_pool, - time_profiler_chan.clone(), LoadPlaceholder::Preload) - }; - + let image_cache_task = new_image_cache_task(resource_task.clone()); let font_cache_task = FontCacheTask::new(resource_task.clone()); let storage_task: StorageTask = StorageTaskFactory::new(); diff --git a/ports/gonk/src/lib.rs b/ports/gonk/src/lib.rs index d319d76574c..6d4a2d517bb 100644 --- a/ports/gonk/src/lib.rs +++ b/ports/gonk/src/lib.rs @@ -39,12 +39,10 @@ use msg::constellation_msg::ConstellationChan; use script::dom::bindings::codegen::RegisterBindings; #[cfg(not(test))] -use net::image_cache_task::{ImageCacheTaskFactory, LoadPlaceholder}; +use net::image_cache_task::new_image_cache_task; #[cfg(not(test))] use net::storage_task::StorageTaskFactory; #[cfg(not(test))] -use net_traits::image_cache_task::ImageCacheTask; -#[cfg(not(test))] use net::resource_task::new_resource_task; #[cfg(not(test))] use gfx::font_cache_task::FontCacheTask; @@ -108,17 +106,7 @@ impl Browser { // Create a Servo instance. let resource_task = new_resource_task(opts.user_agent.clone()); - // If we are emitting an output file, then we need to block on - // image load or we risk emitting an output file missing the - // image. - let image_cache_task: ImageCacheTask = if opts.output_file.is_some() { - ImageCacheTaskFactory::new_sync(resource_task.clone(), shared_task_pool, - time_profiler_chan.clone(), LoadPlaceholder::Preload) - } else { - ImageCacheTaskFactory::new(resource_task.clone(), shared_task_pool, - time_profiler_chan.clone(), LoadPlaceholder::Preload) - }; - + let image_cache_task = new_image_cache_task(resource_task.clone()); let font_cache_task = FontCacheTask::new(resource_task.clone()); let storage_task = StorageTaskFactory::new(); diff --git a/tests/unit/net/image_cache_task.rs b/tests/unit/net/image_cache_task.rs deleted file mode 100644 index 6715fe8cf75..00000000000 --- a/tests/unit/net/image_cache_task.rs +++ /dev/null @@ -1,574 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use net::image_cache_task::*; -use net_traits::image_cache_task::ImageResponseMsg::*; -use net_traits::image_cache_task::Msg::*; - -use net::resource_task::{start_sending, ProgressSender}; -use net_traits::{ControlMsg, Metadata, ResourceTask}; -use net_traits::image_cache_task::{ImageCacheTask, ImageCacheTaskClient, ImageResponseMsg, Msg}; -use net_traits::ProgressMsg::{Payload, Done}; -use profile::time; -use std::sync::mpsc::{Sender, channel, Receiver}; -use url::Url; -use util::taskpool::TaskPool; - -static TEST_IMAGE: &'static [u8] = include_bytes!("test.jpeg"); - -pub fn test_image_bin() -> Vec { - TEST_IMAGE.iter().map(|&x| x).collect() -} - -trait ImageCacheTaskHelper { - fn wait_for_store(&self) -> Receiver<()>; - fn wait_for_store_prefetched(&self) -> Receiver<()>; -} - -impl ImageCacheTaskHelper for ImageCacheTask { - fn wait_for_store(&self) -> Receiver<()> { - let (chan, port) = channel(); - self.send(Msg::WaitForStore(chan)); - port - } - - fn wait_for_store_prefetched(&self) -> Receiver<()> { - let (chan, port) = channel(); - self.send(Msg::WaitForStorePrefetched(chan)); - port - } -} - -trait Closure { - fn invoke(&self, _response: ProgressSender) { } -} -struct DoesNothing; -impl Closure for DoesNothing { } - -struct JustSendOK { - url_requested_chan: Sender<()>, -} -impl Closure for JustSendOK { - fn invoke(&self, response: ProgressSender) { - self.url_requested_chan.send(()).unwrap(); - response.send(Done(Ok(()))).unwrap(); - } -} - -struct SendTestImage; -impl Closure for SendTestImage { - fn invoke(&self, response: ProgressSender) { - response.send(Payload(test_image_bin())).unwrap(); - response.send(Done(Ok(()))).unwrap(); - } -} - -struct SendBogusImage; -impl Closure for SendBogusImage { - fn invoke(&self, response: ProgressSender) { - response.send(Payload(vec!())).unwrap(); - response.send(Done(Ok(()))).unwrap(); - } -} - -struct SendTestImageErr; -impl Closure for SendTestImageErr { - fn invoke(&self, response: ProgressSender) { - response.send(Payload(test_image_bin())).unwrap(); - response.send(Done(Err("".to_string()))).unwrap(); - } -} - -struct WaitSendTestImage { - wait_port: Receiver<()>, -} -impl Closure for WaitSendTestImage { - fn invoke(&self, response: ProgressSender) { - // Don't send the data until after the client requests - // the image - self.wait_port.recv().unwrap(); - response.send(Payload(test_image_bin())).unwrap(); - response.send(Done(Ok(()))).unwrap(); - } -} - -struct WaitSendTestImageErr { - wait_port: Receiver<()>, -} -impl Closure for WaitSendTestImageErr { - fn invoke(&self, response: ProgressSender) { - // Don't send the data until after the client requests - // the image - self.wait_port.recv().unwrap(); - response.send(Payload(test_image_bin())).unwrap(); - response.send(Done(Err("".to_string()))).unwrap(); - } -} - -fn mock_resource_task(on_load: Box) -> ResourceTask { - spawn_listener(move |port: Receiver| { - loop { - match port.recv().unwrap() { - ControlMsg::Load(_, consumer) => { - let chan = start_sending(consumer, Metadata::default( - Url::parse("file:///fake").unwrap())); - on_load.invoke(chan); - } - ControlMsg::Exit => break, - _ => {} - } - } - }) -} - -fn profiler() -> time::ProfilerChan { - time::Profiler::create(None) -} - -#[test] -fn should_exit_on_request() { - let mock_resource_task = mock_resource_task(Box::new(DoesNothing)); - - let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(), - TaskPool::new(4), profiler(), - LoadPlaceholder::Ignore); - - image_cache_task.exit(); - mock_resource_task.send(ControlMsg::Exit).unwrap(); -} - -#[test] -#[should_panic] -fn should_panic_if_unprefetched_image_is_requested() { - let mock_resource_task = mock_resource_task(Box::new(DoesNothing)); - - let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(), - TaskPool::new(4), profiler(), - LoadPlaceholder::Preload); - let url = Url::parse("file:///").unwrap(); - - let (chan, port) = channel(); - image_cache_task.send(Msg::GetImage(url, chan)); - port.recv().unwrap(); -} - -#[test] -fn should_request_url_from_resource_task_on_prefetch() { - let (url_requested_chan, url_requested) = channel(); - - let mock_resource_task = mock_resource_task(Box::new(JustSendOK { url_requested_chan: url_requested_chan})); - - let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(), - TaskPool::new(4), profiler(), - LoadPlaceholder::Preload); - let url = Url::parse("file:///").unwrap(); - - image_cache_task.send(Prefetch(url)); - url_requested.recv().unwrap(); - image_cache_task.exit(); - mock_resource_task.send(ControlMsg::Exit).unwrap(); -} - -#[test] -fn should_not_request_url_from_resource_task_on_multiple_prefetches() { - let (url_requested_chan, url_requested) = channel(); - - let mock_resource_task = mock_resource_task(Box::new(JustSendOK { url_requested_chan: url_requested_chan})); - - let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(), - TaskPool::new(4), profiler(), - LoadPlaceholder::Ignore); - let url = Url::parse("file:///").unwrap(); - - image_cache_task.send(Prefetch(url.clone())); - image_cache_task.send(Prefetch(url)); - url_requested.recv().unwrap(); - image_cache_task.exit(); - mock_resource_task.send(ControlMsg::Exit).unwrap(); - match url_requested.try_recv() { - Err(_) => (), - Ok(_) => panic!(), - }; -} - -#[test] -fn should_return_image_not_ready_if_data_has_not_arrived() { - let (wait_chan, wait_port) = channel(); - - let mock_resource_task = mock_resource_task(Box::new(WaitSendTestImage{wait_port: wait_port})); - - let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(), - TaskPool::new(4), profiler(), - LoadPlaceholder::Ignore); - let url = Url::parse("file:///").unwrap(); - - image_cache_task.send(Prefetch(url.clone())); - image_cache_task.send(Decode(url.clone())); - let (response_chan, response_port) = channel(); - image_cache_task.send(Msg::GetImage(url, response_chan)); - assert!(response_port.recv().unwrap() == ImageResponseMsg::ImageNotReady); - wait_chan.send(()).unwrap(); - image_cache_task.exit(); - mock_resource_task.send(ControlMsg::Exit).unwrap(); -} - -#[test] -fn should_return_decoded_image_data_if_data_has_arrived() { - let mock_resource_task = mock_resource_task(Box::new(SendTestImage)); - - let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(), - TaskPool::new(4), profiler(), - LoadPlaceholder::Preload); - let url = Url::parse("file:///").unwrap(); - - let join_port = image_cache_task.wait_for_store(); - - image_cache_task.send(Prefetch(url.clone())); - image_cache_task.send(Decode(url.clone())); - - // Wait until our mock resource task has sent the image to the image cache - join_port.recv().unwrap(); - - let (response_chan, response_port) = channel(); - image_cache_task.send(Msg::GetImage(url, response_chan)); - match response_port.recv().unwrap() { - ImageResponseMsg::ImageReady(_) => (), - _ => panic!("bleh") - } - - image_cache_task.exit(); - mock_resource_task.send(ControlMsg::Exit).unwrap(); -} - -#[test] -fn should_return_decoded_image_data_for_multiple_requests() { - let mock_resource_task = mock_resource_task(Box::new(SendTestImage)); - - let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(), - TaskPool::new(4), profiler(), - LoadPlaceholder::Preload); - let url = Url::parse("file:///").unwrap(); - - let join_port = image_cache_task.wait_for_store(); - - image_cache_task.send(Prefetch(url.clone())); - image_cache_task.send(Decode(url.clone())); - - // Wait until our mock resource task has sent the image to the image cache - join_port.recv().unwrap(); - - for _ in 0..2 { - let (response_chan, response_port) = channel(); - image_cache_task.send(Msg::GetImage(url.clone(), response_chan)); - match response_port.recv().unwrap() { - ImageResponseMsg::ImageReady(_) => (), - _ => panic!("bleh") - } - } - - image_cache_task.exit(); - mock_resource_task.send(ControlMsg::Exit).unwrap(); -} - -#[test] -fn should_not_request_image_from_resource_task_if_image_is_already_available() { - let (image_bin_sent_chan, image_bin_sent) = channel(); - - let (resource_task_exited_chan, resource_task_exited) = channel(); - - let mock_resource_task = spawn_listener(move |port: Receiver| { - loop { - match port.recv().unwrap() { - ControlMsg::Load(_, consumer) => { - let chan = start_sending(consumer, Metadata::default( - Url::parse("file:///fake").unwrap())); - chan.send(Payload(test_image_bin())).unwrap(); - chan.send(Done(Ok(()))).unwrap(); - image_bin_sent_chan.send(()).unwrap(); - } - ControlMsg::Exit => { - resource_task_exited_chan.send(()).unwrap(); - break - } - _ => {} - } - } - }); - - let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(), - TaskPool::new(4), profiler(), - LoadPlaceholder::Ignore); - let url = Url::parse("file:///").unwrap(); - - image_cache_task.send(Prefetch(url.clone())); - - // Wait until our mock resource task has sent the image to the image cache - image_bin_sent.recv().unwrap(); - - image_cache_task.send(Prefetch(url.clone())); - - image_cache_task.exit(); - mock_resource_task.send(ControlMsg::Exit).unwrap(); - - resource_task_exited.recv().unwrap(); - - // Our resource task should not have received another request for the image - // because it's already cached - match image_bin_sent.try_recv() { - Err(_) => (), - Ok(_) => panic!(), - } -} - -#[test] -fn should_not_request_image_from_resource_task_if_image_fetch_already_failed() { - let (image_bin_sent_chan, image_bin_sent) = channel(); - - let (resource_task_exited_chan, resource_task_exited) = channel(); - let mock_resource_task = spawn_listener(move |port: Receiver| { - loop { - match port.recv().unwrap() { - ControlMsg::Load(_, consumer) => { - let chan = start_sending(consumer, Metadata::default( - Url::parse("file:///fake").unwrap())); - chan.send(Payload(test_image_bin())).unwrap(); - chan.send(Done(Err("".to_string()))).unwrap(); - image_bin_sent_chan.send(()).unwrap(); - } - ControlMsg::Exit => { - resource_task_exited_chan.send(()).unwrap(); - break - } - _ => {} - } - } - }); - - let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(), - TaskPool::new(4), profiler(), - LoadPlaceholder::Ignore); - let url = Url::parse("file:///").unwrap(); - - image_cache_task.send(Prefetch(url.clone())); - image_cache_task.send(Decode(url.clone())); - - // Wait until our mock resource task has sent the image to the image cache - image_bin_sent.recv().unwrap(); - - image_cache_task.send(Prefetch(url.clone())); - image_cache_task.send(Decode(url.clone())); - - image_cache_task.exit(); - mock_resource_task.send(ControlMsg::Exit).unwrap(); - - resource_task_exited.recv().unwrap(); - - // Our resource task should not have received another request for the image - // because it's already cached - match image_bin_sent.try_recv() { - Err(_) => (), - Ok(_) => panic!(), - } -} - -#[test] -fn should_return_failed_if_image_bin_cannot_be_fetched() { - let mock_resource_task = mock_resource_task(Box::new(SendTestImageErr)); - - let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(), - TaskPool::new(4), profiler(), - LoadPlaceholder::Preload); - let url = Url::parse("file:///").unwrap(); - - let join_port = image_cache_task.wait_for_store_prefetched(); - - image_cache_task.send(Prefetch(url.clone())); - image_cache_task.send(Decode(url.clone())); - - // Wait until our mock resource task has sent the image to the image cache - join_port.recv().unwrap(); - - let (response_chan, response_port) = channel(); - image_cache_task.send(Msg::GetImage(url, response_chan)); - match response_port.recv().unwrap() { - ImageResponseMsg::ImageFailed => (), - _ => panic!("bleh") - } - - image_cache_task.exit(); - mock_resource_task.send(ControlMsg::Exit).unwrap(); -} - -#[test] -fn should_return_failed_for_multiple_get_image_requests_if_image_bin_cannot_be_fetched() { - let mock_resource_task = mock_resource_task(Box::new(SendTestImageErr)); - - let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(), - TaskPool::new(4), profiler(), - LoadPlaceholder::Preload); - let url = Url::parse("file:///").unwrap(); - - let join_port = image_cache_task.wait_for_store_prefetched(); - - image_cache_task.send(Prefetch(url.clone())); - image_cache_task.send(Decode(url.clone())); - - // Wait until our mock resource task has sent the image to the image cache - join_port.recv().unwrap(); - - let (response_chan, response_port) = channel(); - image_cache_task.send(Msg::GetImage(url.clone(), response_chan)); - match response_port.recv().unwrap() { - ImageResponseMsg::ImageFailed => (), - _ => panic!("bleh") - } - - // And ask again, we should get the same response - let (response_chan, response_port) = channel(); - image_cache_task.send(Msg::GetImage(url, response_chan)); - match response_port.recv().unwrap() { - ImageResponseMsg::ImageFailed => (), - _ => panic!("bleh") - } - - image_cache_task.exit(); - mock_resource_task.send(ControlMsg::Exit).unwrap(); -} - -#[test] -fn should_return_failed_if_image_decode_fails() { - let mock_resource_task = mock_resource_task(Box::new(SendBogusImage)); - - let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(), - TaskPool::new(4), profiler(), - LoadPlaceholder::Preload); - let url = Url::parse("file:///").unwrap(); - - let join_port = image_cache_task.wait_for_store(); - - image_cache_task.send(Prefetch(url.clone())); - image_cache_task.send(Decode(url.clone())); - - // Wait until our mock resource task has sent the image to the image cache - join_port.recv().unwrap(); - - // Make the request - let (response_chan, response_port) = channel(); - image_cache_task.send(Msg::GetImage(url, response_chan)); - - match response_port.recv().unwrap() { - ImageResponseMsg::ImageFailed => (), - _ => panic!("bleh") - } - - image_cache_task.exit(); - mock_resource_task.send(ControlMsg::Exit).unwrap(); -} - -#[test] -fn should_return_image_on_wait_if_image_is_already_loaded() { - let mock_resource_task = mock_resource_task(Box::new(SendTestImage)); - - let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(), - TaskPool::new(4), profiler(), - LoadPlaceholder::Preload); - let url = Url::parse("file:///").unwrap(); - - let join_port = image_cache_task.wait_for_store(); - - image_cache_task.send(Prefetch(url.clone())); - image_cache_task.send(Decode(url.clone())); - - // Wait until our mock resource task has sent the image to the image cache - join_port.recv().unwrap(); - - let (response_chan, response_port) = channel(); - image_cache_task.send(Msg::WaitForImage(url, response_chan)); - match response_port.recv().unwrap() { - ImageResponseMsg::ImageReady(..) => (), - _ => panic!("bleh") - } - - image_cache_task.exit(); - mock_resource_task.send(ControlMsg::Exit).unwrap(); -} - -#[test] -fn should_return_image_on_wait_if_image_is_not_yet_loaded() { - let (wait_chan, wait_port) = channel(); - - let mock_resource_task = mock_resource_task(Box::new(WaitSendTestImage {wait_port: wait_port})); - - let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(), - TaskPool::new(4), profiler(), - LoadPlaceholder::Ignore); - let url = Url::parse("file:///").unwrap(); - - image_cache_task.send(Prefetch(url.clone())); - image_cache_task.send(Decode(url.clone())); - - let (response_chan, response_port) = channel(); - image_cache_task.send(Msg::WaitForImage(url, response_chan)); - - wait_chan.send(()).unwrap(); - - match response_port.recv().unwrap() { - ImageResponseMsg::ImageReady(..) => (), - _ => panic!("bleh") - } - - image_cache_task.exit(); - mock_resource_task.send(ControlMsg::Exit).unwrap(); -} - -#[test] -fn should_return_image_failed_on_wait_if_image_fails_to_load() { - let (wait_chan, wait_port) = channel(); - - let mock_resource_task = mock_resource_task(Box::new(WaitSendTestImageErr{wait_port: wait_port})); - - let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new(mock_resource_task.clone(), - TaskPool::new(4), profiler(), - LoadPlaceholder::Ignore); - let url = Url::parse("file:///").unwrap(); - - image_cache_task.send(Prefetch(url.clone())); - image_cache_task.send(Decode(url.clone())); - - let (response_chan, response_port) = channel(); - image_cache_task.send(Msg::WaitForImage(url, response_chan)); - - wait_chan.send(()).unwrap(); - - match response_port.recv().unwrap() { - ImageResponseMsg::ImageFailed => (), - _ => panic!("bleh") - } - - image_cache_task.exit(); - mock_resource_task.send(ControlMsg::Exit).unwrap(); -} - -#[test] -fn sync_cache_should_wait_for_images() { - let mock_resource_task = mock_resource_task(Box::new(SendTestImage)); - - let image_cache_task: ImageCacheTask = ImageCacheTaskFactory::new_sync(mock_resource_task.clone(), - TaskPool::new(4), profiler(), - LoadPlaceholder::Preload); - let url = Url::parse("file:///").unwrap(); - - image_cache_task.send(Prefetch(url.clone())); - image_cache_task.send(Decode(url.clone())); - - let (response_chan, response_port) = channel(); - image_cache_task.send(Msg::GetImage(url, response_chan)); - match response_port.recv().unwrap() { - ImageResponseMsg::ImageReady(_) => (), - _ => panic!("bleh") - } - - image_cache_task.exit(); - mock_resource_task.send(ControlMsg::Exit).unwrap(); -} diff --git a/tests/unit/net/lib.rs b/tests/unit/net/lib.rs index d38edca2617..f44c6fd54cd 100644 --- a/tests/unit/net/lib.rs +++ b/tests/unit/net/lib.rs @@ -12,6 +12,5 @@ extern crate util; #[cfg(test)] mod cookie; #[cfg(test)] mod data_loader; -#[cfg(test)] mod image_cache_task; #[cfg(test)] mod mime_classifier; #[cfg(test)] mod resource_task; diff --git a/tests/wpt/metadata/html/dom/interfaces.html.ini b/tests/wpt/metadata/html/dom/interfaces.html.ini index ffc186782d6..998f512b9e9 100644 --- a/tests/wpt/metadata/html/dom/interfaces.html.ini +++ b/tests/wpt/metadata/html/dom/interfaces.html.ini @@ -2859,15 +2859,6 @@ [HTMLImageElement interface: attribute crossOrigin] expected: FAIL - [HTMLImageElement interface: attribute naturalWidth] - expected: FAIL - - [HTMLImageElement interface: attribute naturalHeight] - expected: FAIL - - [HTMLImageElement interface: attribute complete] - expected: FAIL - [HTMLImageElement interface: attribute currentSrc] expected: FAIL @@ -2883,15 +2874,6 @@ [HTMLImageElement interface: document.createElement("img") must inherit property "crossOrigin" with the proper type (4)] expected: FAIL - [HTMLImageElement interface: document.createElement("img") must inherit property "naturalWidth" with the proper type (9)] - expected: FAIL - - [HTMLImageElement interface: document.createElement("img") must inherit property "naturalHeight" with the proper type (10)] - expected: FAIL - - [HTMLImageElement interface: document.createElement("img") must inherit property "complete" with the proper type (11)] - expected: FAIL - [HTMLImageElement interface: document.createElement("img") must inherit property "currentSrc" with the proper type (12)] expected: FAIL diff --git a/tests/wpt/metadata/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-auto.html.ini b/tests/wpt/metadata/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-auto.html.ini index 5143f4d8154..58aa0a0fb93 100644 --- a/tests/wpt/metadata/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-auto.html.ini +++ b/tests/wpt/metadata/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-auto.html.ini @@ -1,6 +1,650 @@ [svg-in-img-auto.html] type: testharness - expected: TIMEOUT - [placeholder: \'img\', ] - expected: TIMEOUT + [placeholder: \'img\', placeholderWidthAttr: \'100\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', ] + expected: FAIL + + [placeholder: \'img\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', ] + expected: FAIL + + [placeholder: \'img\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL diff --git a/tests/wpt/metadata/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-fixed.html.ini b/tests/wpt/metadata/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-fixed.html.ini index 3dd736dda61..b0d189cbee0 100644 --- a/tests/wpt/metadata/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-fixed.html.ini +++ b/tests/wpt/metadata/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-fixed.html.ini @@ -1,6 +1,650 @@ [svg-in-img-fixed.html] type: testharness - expected: TIMEOUT [placeholder: \'img\', placeholderHeightAttr: \'100px\', ] - expected: TIMEOUT + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100px\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100px\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL diff --git a/tests/wpt/metadata/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-percentage.html.ini b/tests/wpt/metadata/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-percentage.html.ini index 03f61242dd9..b2a89ff5f7e 100644 --- a/tests/wpt/metadata/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-percentage.html.ini +++ b/tests/wpt/metadata/html/rendering/replaced-elements/svg-embedded-sizing/svg-in-img-percentage.html.ini @@ -1,6 +1,650 @@ [svg-in-img-percentage.html] type: testharness - expected: TIMEOUT - [placeholder: \'img\', placeholderHeightAttr: \'100%\', ] - expected: TIMEOUT + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', containerHeightStyle: \'400px\', placeholderWidthAttr: \'50%\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderWidthAttr: \'100\', placeholderHeightAttr: \'100%\', svgViewBoxAttr: \'0 0 100 200\', svgWidthAttr: \'200\', svgHeightAttr: \'200\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL + + [placeholder: \'img\', containerWidthStyle: \'400px\', placeholderHeightAttr: \'100%\', svgWidthAttr: \'25%\', svgHeightAttr: \'25%\', ] + expected: FAIL diff --git a/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/relevant-mutations.html.ini b/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/relevant-mutations.html.ini index db509383662..9100a15ea44 100644 --- a/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/relevant-mutations.html.ini +++ b/tests/wpt/metadata/html/semantics/embedded-content/the-img-element/relevant-mutations.html.ini @@ -1,11 +1,5 @@ [relevant-mutations.html] type: testharness - [src set] - expected: FAIL - - [src changed] - expected: FAIL - [src removed] expected: FAIL @@ -27,9 +21,6 @@ [sizes removed] expected: FAIL - [src set to same value] - expected: FAIL - [crossorigin absent to empty] expected: FAIL @@ -60,51 +51,84 @@ [crossorigin use-credentials to anonymous] expected: FAIL - [inserted into picture] + [crossorigin state not changed: absent, removeAttribute] expected: FAIL - [removed from picture] + [crossorigin state not changed: empty to anonymous] expected: FAIL - [parent is picture, previous source inserted] + [crossorigin state not changed: anonymous to foobar] expected: FAIL - [parent is picture, previous source removed] + [crossorigin state not changed: use-credentials to USE-CREDENTIALS] expected: FAIL - [parent is picture, previous source has srcset set] + [inserted into picture ancestor] expected: FAIL - [parent is picture, previous source has srcset changed] + [removed from picture ancestor] expected: FAIL - [parent is picture, previous source has srcset removed] + [ancestor picture has a source inserted] expected: FAIL - [parent is picture, previous source has sizes set] + [ancestor picture has a source removed] expected: FAIL - [parent is picture, previous source has sizes changed] + [ancestor picture; previous sibling source inserted] expected: FAIL - [parent is picture, previous source has sizes removed] + [ancestor picture; previous sibling source removed] expected: FAIL - [parent is picture, previous source has media set] + [parent is picture, following sibling source inserted] expected: FAIL - [parent is picture, previous source has media changed] + [parent is picture, following sibling source removed] expected: FAIL - [parent is picture, previous source has media removed] + [parent is picture, following sibling source has srcset set] expected: FAIL - [parent is picture, previous source has type set] + [media on img set] expected: FAIL - [parent is picture, previous source has type changed] + [type on img set] expected: FAIL - [parent is picture, previous source has type removed] + [class on img set] + expected: FAIL + + [alt on img set] + expected: FAIL + + [src on previous sibling source set] + expected: FAIL + + [class on previous sibling source set] + expected: FAIL + + [inserted/removed children of img] + expected: FAIL + + [picture is inserted] + expected: FAIL + + [picture is removed] + expected: FAIL + + [parent is picture, following img inserted] + expected: FAIL + + [parent is picture, following img removed] + expected: FAIL + + [parent is picture, following img has src set] + expected: FAIL + + [parent is picture, following img has srcset set] + expected: FAIL + + [parent is picture, following img has sizes set] expected: FAIL diff --git a/tests/wpt/mozilla/tests/mozilla/img_width_height.html b/tests/wpt/mozilla/tests/mozilla/img_width_height.html index c792668083c..8fa0f597ac9 100644 --- a/tests/wpt/mozilla/tests/mozilla/img_width_height.html +++ b/tests/wpt/mozilla/tests/mozilla/img_width_height.html @@ -11,22 +11,14 @@ async_test(function() { var img = window.document.getElementsByTagName("img")[0]; - var wait_for_img_load = this.step_func(function (f) { - if (img.width != 0) { - f(); - } else { - window.setTimeout(function() { wait_for_img_load(f) }, 1); - } - }); - - wait_for_img_load(this.step_func_done(function() { + img.onload = this.step_func_done(function() { assert_equals(img.width, 500); assert_equals(img.height, 378); img.width = 200; img.height = 100; assert_equals(img.width, 200); assert_equals(img.height, 100); - })); + }); });