scripts/IMAGE_PIPELINE_ANALYSIS.md
The image rendering system is currently broken because images are not being properly passed through the display list to the WebRender backend. This document analyzes the current architecture and proposes a complete redesign.
Images can come from multiple sources in Azul:
DOM Content Images (NodeType::Image(ImageRef))
Dom::image()CSS Background Images (StyleBackgroundContent::Image(AzString))
background-image: url("...") in CSSNoneInline Images (InlineContent::Image { source: ImageSource })
ImageSource is an empty stub structIcon Images (from IconProviderHandle)
┌─────────────────────────────────────────────────────────────────────────────┐
│ 1. DOM Creation │
│ - User creates Dom with NodeType::Image(ImageRef) │
│ - CSS parsed with background-image: url("...") → AzString only │
└───────────────────────────────────┬─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 2. Layout Phase │
│ - Images need intrinsic size for layout calculations │
│ - NodeType::Image → can get size from ImageRef.get_data() │
│ - CSS background-image → ??? No ImageRef available, only AzString! │
└───────────────────────────────────┬─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 3. Display List Generation │
│ - DisplayListItem::Image { bounds, image: ImageRef } │
│ - NodeType::Image → works, stores ImageRef directly │
│ - CSS background-image → BROKEN: get_image_ref_for_image_source() = None │
└───────────────────────────────────┬─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 4. Resource Collection (build_webrender_transaction) │
│ - Scans display list for DisplayListItem::Image │
│ - Extracts ImageRef and creates AddImage messages │
│ - Registers in currently_registered_images │
└───────────────────────────────────┬─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 5. WebRender Compositing (compositor2.rs) │
│ - Looks up ImageRef.get_hash() in currently_registered_images │
│ - Calls builder.push_image() with WebRender ImageKey │
└─────────────────────────────────────────────────────────────────────────────┘
Location: css/src/props/style/background.rs:67
pub enum StyleBackgroundContent {
LinearGradient(LinearGradient),
RadialGradient(RadialGradient),
ConicGradient(ConicGradient),
Image(AzString), // ← Only stores the CSS url string!
Color(ColorU),
}
The CSS parser only stores the URL string, not the actual image data. We need:
ImageCache lookup during styling/layoutAzString → ImageRefLocation: layout/src/font_traits.rs:204
#[derive(Debug, Clone)]
pub struct ImageSource; // ← Empty struct!
This is used for inline images but has no actual implementation.
Location: layout/src/solver3/display_list.rs:795
StyleBackgroundContent::Image(_image_id) => {
// TODO: Implement image backgrounds
}
Background images are completely ignored during display list generation.
The ImageCache exists but is not accessible during display list generation:
Location: core/src/resources.rs:628
pub struct ImageCache {
pub image_id_map: FastHashMap<AzString, ImageRef>,
}
This maps CSS url("...") strings to ImageRef, but it's not available in DisplayListContext.
image_cache: &ImageCache to LayoutContextimage_cache: &ImageCache to DisplayListContextpush_backgrounds_and_border() to look up background images// In display_list.rs
StyleBackgroundContent::Image(image_id) => {
if let Some(image_ref) = self.image_cache.get_css_image_id(image_id) {
self.push_image(bounds, image_ref.clone());
}
}
Replace the stub ImageSource with a real type:
pub enum ImageSource {
/// Direct reference to decoded image
Ref(ImageRef),
/// CSS url reference (needs ImageCache lookup)
Url(AzString),
/// Generated image (e.g., SVG icon)
Generated {
width: u32,
height: u32,
data: Vec<u8>
},
}
For layout, we need image dimensions before rendering:
impl ImageSource {
pub fn get_intrinsic_size(&self, image_cache: &ImageCache) -> Option<(u32, u32)> {
match self {
ImageSource::Ref(img) => img.get_dimensions(),
ImageSource::Url(url) => {
image_cache.get_css_image_id(url)
.and_then(|img| img.get_dimensions())
}
ImageSource::Generated { width, height, .. } => Some((*width, *height)),
}
}
}
| Location | TODO | Impact |
|---|---|---|
display_list.rs:795 | Implement image backgrounds | CSS background-image completely broken |
display_list.rs:846 | Implement image backgrounds for inline text | Inline background-image broken |
display_list.rs:2776 | ImageSource needs to contain ImageRef | Inline images completely broken |
cpurender.rs:935 | Implement actual image blitting | CPU rendering shows placeholder only |
window.rs:1228 | Scan styled_dom for image references | Images not pre-loaded |
| Location | TODO | Impact |
|---|---|---|
compositor2.rs:1647 | Implement proper WebRender box shadow | Box shadows not rendered |
compositor2.rs:1686 | Implement proper WebRender filter stacking | CSS filters don't work |
compositor2.rs:1710 | Implement proper WebRender backdrop filter | backdrop-filter broken |
compositor2.rs:1734 | Implement proper WebRender opacity stacking | Opacity layers broken |
cpurender.rs:450 | Implement proper gradient rendering | Gradients show placeholder |
cpurender.rs:540 | Implement proper box shadow rendering | CPU shadows not rendered |
| Location | TODO | Impact |
|---|---|---|
menu_renderer.rs:423 | Render image icon | Menu icons not shown |
display_list.rs:2383-2387 | Text decorations/shadows/overflow | Text styling incomplete |
fc.rs:3635-3636 | colspan/rowspan from CSS | Table layout incomplete |
shape_parser.rs:289 | Handle em, rem, vh, vw | Relative units in shapes broken |
image_cache: &ImageCache parameter to LayoutContextimage_cache: &ImageCache parameter to DisplayListContextStyleBackgroundContent::Image handling in push_backgrounds_and_border()StyleBackgroundContent::Image handling in push_inline_backgrounds_and_border()ImageSource stub with real enumget_image_ref_for_image_source() functionDecodedImagecore/src/resources.rs
get_dimensions() to ImageRef/DecodedImagelayout/src/font_traits.rs
ImageSource stub with real implementationlayout/src/solver3/display_list.rs
image_cache field to DisplayListContextStyleBackgroundContent::Image handlingget_image_ref_for_image_source()layout/src/window.rs
ImageCache through to layout functionsdll/src/desktop/shell2/common/layout_v2.rs
ImageCache to layout_and_generate_display_list()background-image: url(...) renders correctly