mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
layout: Add support for <object>
with image data URLs (#32069)
This is enough support for `<object>` to get Acid2 working. Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
a77c15ee16
commit
f379041597
8 changed files with 76 additions and 9 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -3091,6 +3091,7 @@ dependencies = [
|
|||
"bitflags 2.5.0",
|
||||
"canvas_traits",
|
||||
"cssparser",
|
||||
"data-url",
|
||||
"embedder_traits",
|
||||
"euclid",
|
||||
"fnv",
|
||||
|
@ -3119,6 +3120,7 @@ dependencies = [
|
|||
"style_traits",
|
||||
"unicode-script",
|
||||
"unicode-segmentation",
|
||||
"url",
|
||||
"webrender_api",
|
||||
"xi-unicode",
|
||||
]
|
||||
|
|
|
@ -44,6 +44,8 @@ style = { workspace = true }
|
|||
style_traits = { workspace = true }
|
||||
unicode-script = { workspace = true }
|
||||
unicode-segmentation = { workspace = true }
|
||||
url = { workspace = true }
|
||||
data-url = { workspace = true }
|
||||
webrender_api = { workspace = true }
|
||||
xi-unicode = { workspace = true }
|
||||
|
||||
|
|
|
@ -6,10 +6,15 @@ use std::marker::PhantomData;
|
|||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
|
||||
use html5ever::{local_name, namespace_url, ns};
|
||||
use msg::constellation_msg::{BrowsingContextId, PipelineId};
|
||||
use net_traits::image::base::Image as NetImage;
|
||||
use script_layout_interface::wrapper_traits::{LayoutDataTrait, LayoutNode, ThreadSafeLayoutNode};
|
||||
use script_layout_interface::HTMLCanvasDataSource;
|
||||
use script_layout_interface::wrapper_traits::{
|
||||
LayoutDataTrait, LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
|
||||
};
|
||||
use script_layout_interface::{
|
||||
HTMLCanvasDataSource, LayoutElementType, LayoutNodeType as ScriptLayoutNodeType,
|
||||
};
|
||||
use servo_arc::Arc as ServoArc;
|
||||
use style::properties::ComputedValues;
|
||||
|
||||
|
@ -95,6 +100,7 @@ pub(crate) trait NodeExt<'dom>: 'dom + LayoutNode<'dom> {
|
|||
fn as_canvas(self) -> Option<(CanvasInfo, PhysicalSize<f64>)>;
|
||||
fn as_iframe(self) -> Option<(PipelineId, BrowsingContextId)>;
|
||||
fn as_video(self) -> Option<(webrender_api::ImageKey, PhysicalSize<f64>)>;
|
||||
fn as_typeless_object_with_data_attribute(self) -> Option<String>;
|
||||
fn style(self, context: &LayoutContext) -> ServoArc<ComputedValues>;
|
||||
|
||||
fn layout_data_mut(self) -> AtomicRefMut<'dom, InnerDOMLayoutData>;
|
||||
|
@ -163,6 +169,25 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn as_typeless_object_with_data_attribute(self) -> Option<String> {
|
||||
if self.type_id() != ScriptLayoutNodeType::Element(LayoutElementType::HTMLObjectElement) {
|
||||
return None;
|
||||
}
|
||||
let Some(element) = self.to_threadsafe().as_element() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
// TODO: This is the what the legacy layout system does, but really if Servo
|
||||
// supports any `<object>` that's an image, it should support those with URLs
|
||||
// and `type` attributes with image mime types.
|
||||
if element.get_attr(&ns!(), &local_name!("type")).is_some() {
|
||||
return None;
|
||||
}
|
||||
element
|
||||
.get_attr(&ns!(), &local_name!("data"))
|
||||
.map(|string| string.to_owned())
|
||||
}
|
||||
|
||||
fn style(self, context: &LayoutContext) -> ServoArc<ComputedValues> {
|
||||
self.to_threadsafe().style(context.shared_context())
|
||||
}
|
||||
|
|
|
@ -175,7 +175,7 @@ fn traverse_element<'dom, Node>(
|
|||
) where
|
||||
Node: NodeExt<'dom>,
|
||||
{
|
||||
let replaced = ReplacedContent::for_element(element);
|
||||
let replaced = ReplacedContent::for_element(element, context);
|
||||
let style = element.style(context);
|
||||
match Display::from(style.get_box().display) {
|
||||
Display::None => element.unset_all_boxes(),
|
||||
|
|
|
@ -204,7 +204,7 @@ impl BoxTree {
|
|||
|
||||
loop {
|
||||
if let Some((primary_style, display_inside, update_point)) = update_point(dirty_node) {
|
||||
let contents = ReplacedContent::for_element(dirty_node)
|
||||
let contents = ReplacedContent::for_element(dirty_node, context)
|
||||
.map_or(Contents::OfElement, Contents::Replaced);
|
||||
let info = NodeAndStyleInfo::new(dirty_node, Arc::clone(&primary_style));
|
||||
let out_of_flow_absolutely_positioned_box = ArcRefCell::new(
|
||||
|
@ -262,8 +262,8 @@ fn construct_for_root_element<'dom>(
|
|||
Display::GeneratingBox(display_generating_box) => display_generating_box.display_inside(),
|
||||
};
|
||||
|
||||
let contents =
|
||||
ReplacedContent::for_element(root_element).map_or(Contents::OfElement, Contents::Replaced);
|
||||
let contents = ReplacedContent::for_element(root_element, context)
|
||||
.map_or(Contents::OfElement, Contents::Replaced);
|
||||
let root_box = if box_style.position.is_absolutely_positioned() {
|
||||
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(ArcRefCell::new(
|
||||
AbsolutelyPositionedBox::construct(context, &info, display_inside, contents),
|
||||
|
|
|
@ -7,6 +7,7 @@ use std::sync::{Arc, Mutex};
|
|||
|
||||
use app_units::Au;
|
||||
use canvas_traits::canvas::{CanvasId, CanvasMsg, FromLayoutMsg};
|
||||
use data_url::DataUrl;
|
||||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use msg::constellation_msg::{BrowsingContextId, PipelineId};
|
||||
use net_traits::image::base::Image;
|
||||
|
@ -19,6 +20,7 @@ use style::values::computed::image::Image as ComputedImage;
|
|||
use style::values::computed::{Length, LengthOrAuto};
|
||||
use style::values::CSSFloat;
|
||||
use style::Zero;
|
||||
use url::Url;
|
||||
use webrender_api::ImageKey;
|
||||
|
||||
use crate::context::LayoutContext;
|
||||
|
@ -131,7 +133,17 @@ pub(crate) enum ReplacedContentKind {
|
|||
}
|
||||
|
||||
impl ReplacedContent {
|
||||
pub fn for_element<'dom>(element: impl NodeExt<'dom>) -> Option<Self> {
|
||||
pub fn for_element<'dom>(element: impl NodeExt<'dom>, context: &LayoutContext) -> Option<Self> {
|
||||
if let Some(ref data_attribute_string) = element.as_typeless_object_with_data_attribute() {
|
||||
if let Some(url) = try_to_parse_image_data_url(data_attribute_string) {
|
||||
return Self::from_image_url(
|
||||
element,
|
||||
context,
|
||||
&ComputedUrl::Valid(ServoArc::new(url)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let (kind, intrinsic_size_in_dots) = {
|
||||
if let Some((image, intrinsic_size_in_dots)) = element.as_image() {
|
||||
(
|
||||
|
@ -558,3 +570,28 @@ impl ReplacedContent {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_to_parse_image_data_url(string: &str) -> Option<Url> {
|
||||
if !string.starts_with("data:") {
|
||||
return None;
|
||||
}
|
||||
let Some(data_url) = DataUrl::process(string).ok() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let mime_type = data_url.mime_type();
|
||||
if mime_type.type_ != "image" {
|
||||
return None;
|
||||
}
|
||||
|
||||
// TODO: Find a better way to test for supported image formats. Currently this type of check is
|
||||
// repeated several places in Servo, but should be centralized somehow.
|
||||
if !matches!(
|
||||
mime_type.subtype.as_str(),
|
||||
"png" | "jpeg" | "gif" | "webp" | "bmp" | "ico"
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
|
||||
Url::parse(string).ok()
|
||||
}
|
||||
|
|
|
@ -34,3 +34,6 @@
|
|||
|
||||
[The table cell width calculation quirk, non-auto width on cell]
|
||||
expected: FAIL
|
||||
|
||||
[The table cell width calculation quirk, the quirk shouldn't apply for <object>]
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
[object_element_a.html]
|
||||
expected: FAIL
|
Loading…
Add table
Add a link
Reference in a new issue