mirror of
https://github.com/servo/servo.git
synced 2025-07-31 03:00:29 +01:00
Add support for static SVG images using resvg
crate (#36721)
This change adds support for rendering static SVG images using the `resvg` crate, allowing svg sources in the `img` tag and in CSS `background` and `content` properties. There are some limitations in using resvg: 1. There is no support for animations or interactivity as these would require implementing the full DOM layer of SVG specification. 2. Only system fonts can be used for text rendering. There is some mechanism to provide a custom font resolver to usvg, but that is not explored in this change. 3. resvg's handling of certain edge cases involving lack of explicit `width` and `height` on the root svg element deviates from what the specification expects from browsers. For example, resvg uses the values in `viewBox` to derive the missing width or height dimension, but without scaling that dimension to preserve the aspect ratio. It also doesn't allow overriding this behavior. Demo screenshot:  <details> <summary>Source</summary> ``` <style> #svg1 { border: 1px solid red; } #svg2 { border: 1px solid red; width: 300px; } #svg3 { border: 1px solid red; width: 300px; height: 200px; object-fit: contain; } #svg4 { border: 1px solid red; width: 300px; height: 200px; object-fit: cover; } #svg5 { border: 1px solid red; width: 300px; height: 200px; object-fit: fill; } #svg6 { border: 1px solid red; width: 300px; height: 200px; object-fit: none; } </style> </head> <body> <div> <img id="svg1" src="https://raw.githubusercontent.com/servo/servo/refs/heads/main/resources/servo.svg" alt="Servo logo"> </div> <div> <img id="svg2" src="https://raw.githubusercontent.com/servo/servo/refs/heads/main/resources/servo.svg" alt="Servo logo"> <img id="svg3" src="https://raw.githubusercontent.com/servo/servo/refs/heads/main/resources/servo.svg" alt="Servo logo"> <img id="svg4" src="https://raw.githubusercontent.com/servo/servo/refs/heads/main/resources/servo.svg" alt="Servo logo"> </div> <div> <img id="svg5" src="https://raw.githubusercontent.com/servo/servo/refs/heads/main/resources/servo.svg" alt="Servo logo"> <img id="svg6" src="https://raw.githubusercontent.com/servo/servo/refs/heads/main/resources/servo.svg" alt="Servo logo"> </div> </body> ``` </details> --------- Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com> Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
324196351e
commit
8a20e42de4
267 changed files with 2374 additions and 544 deletions
|
@ -30,7 +30,7 @@ use libc::c_void;
|
|||
use malloc_size_of::{MallocSizeOf as MallocSizeOfTrait, MallocSizeOfOps};
|
||||
use malloc_size_of_derive::MallocSizeOf;
|
||||
use net_traits::image_cache::{ImageCache, PendingImageId};
|
||||
use pixels::Image;
|
||||
use pixels::RasterImage;
|
||||
use profile_traits::mem::Report;
|
||||
use profile_traits::time;
|
||||
use script_traits::{InitialScriptState, Painter, ScriptThreadMessage};
|
||||
|
@ -49,6 +49,7 @@ use style::properties::style_structs::Font;
|
|||
use style::selector_parser::{PseudoElement, RestyleDamage, Snapshot};
|
||||
use style::stylesheets::Stylesheet;
|
||||
use webrender_api::ImageKey;
|
||||
use webrender_api::units::DeviceIntSize;
|
||||
|
||||
pub trait GenericLayoutDataTrait: Any + MallocSizeOfTrait {
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
|
@ -153,6 +154,16 @@ pub struct PendingImage {
|
|||
pub origin: ImmutableOrigin,
|
||||
}
|
||||
|
||||
/// A data structure to tarck vector image that are fully loaded (i.e has a parsed SVG
|
||||
/// tree) but not yet rasterized to the size needed by layout. The rasterization is
|
||||
/// happening in the image cache.
|
||||
#[derive(Debug)]
|
||||
pub struct PendingRasterizationImage {
|
||||
pub node: UntrustedNodeAddress,
|
||||
pub id: PendingImageId,
|
||||
pub size: DeviceIntSize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct MediaFrame {
|
||||
pub image_key: webrender_api::ImageKey,
|
||||
|
@ -392,6 +403,8 @@ pub type IFrameSizes = FnvHashMap<BrowsingContextId, IFrameSize>;
|
|||
pub struct ReflowResult {
|
||||
/// The list of images that were encountered that are in progress.
|
||||
pub pending_images: Vec<PendingImage>,
|
||||
/// The list of vector images that were encountered that still need to be rasterized.
|
||||
pub pending_rasterization_images: Vec<PendingRasterizationImage>,
|
||||
/// The list of iframes in this layout and their sizes, used in order
|
||||
/// to communicate them with the Constellation and also the `Window`
|
||||
/// element of their content pages.
|
||||
|
@ -507,13 +520,13 @@ pub fn node_id_from_scroll_id(id: usize) -> Option<usize> {
|
|||
#[derive(Clone, Debug, MallocSizeOf)]
|
||||
pub struct ImageAnimationState {
|
||||
#[ignore_malloc_size_of = "Arc is hard"]
|
||||
pub image: Arc<Image>,
|
||||
pub image: Arc<RasterImage>,
|
||||
pub active_frame: usize,
|
||||
last_update_time: f64,
|
||||
}
|
||||
|
||||
impl ImageAnimationState {
|
||||
pub fn new(image: Arc<Image>, last_update_time: f64) -> Self {
|
||||
pub fn new(image: Arc<RasterImage>, last_update_time: f64) -> Self {
|
||||
Self {
|
||||
image,
|
||||
active_frame: 0,
|
||||
|
@ -579,7 +592,7 @@ mod test {
|
|||
use std::time::Duration;
|
||||
|
||||
use ipc_channel::ipc::IpcSharedMemory;
|
||||
use pixels::{CorsStatus, Image, ImageFrame, PixelFormat};
|
||||
use pixels::{CorsStatus, ImageFrame, ImageMetadata, PixelFormat, RasterImage};
|
||||
|
||||
use crate::ImageAnimationState;
|
||||
|
||||
|
@ -593,9 +606,11 @@ mod test {
|
|||
})
|
||||
.take(10)
|
||||
.collect();
|
||||
let image = Image {
|
||||
width: 100,
|
||||
height: 100,
|
||||
let image = RasterImage {
|
||||
metadata: ImageMetadata {
|
||||
width: 100,
|
||||
height: 100,
|
||||
},
|
||||
format: PixelFormat::BGRA8,
|
||||
id: None,
|
||||
bytes: IpcSharedMemory::from_byte(1, 1),
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc as StdArc;
|
||||
|
||||
use atomic_refcell::AtomicRef;
|
||||
use base::id::{BrowsingContextId, PipelineId};
|
||||
use fonts_traits::ByteIndex;
|
||||
use html5ever::{LocalName, Namespace};
|
||||
use pixels::{Image, ImageMetadata};
|
||||
use net_traits::image_cache::Image;
|
||||
use pixels::ImageMetadata;
|
||||
use range::Range;
|
||||
use servo_arc::Arc;
|
||||
use servo_url::ServoUrl;
|
||||
|
@ -222,7 +222,7 @@ pub trait ThreadSafeLayoutNode<'dom>: Clone + Copy + Debug + NodeInfo + PartialE
|
|||
fn image_density(&self) -> Option<f64>;
|
||||
|
||||
/// If this is an image element, returns its image data. Otherwise, returns `None`.
|
||||
fn image_data(&self) -> Option<(Option<StdArc<Image>>, Option<ImageMetadata>)>;
|
||||
fn image_data(&self) -> Option<(Option<Image>, Option<ImageMetadata>)>;
|
||||
|
||||
fn canvas_data(&self) -> Option<HTMLCanvasData>;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue