diff --git a/crates/browser/src/main.rs b/crates/browser/src/main.rs index d821388..2fe4ad6 100644 --- a/crates/browser/src/main.rs +++ b/crates/browser/src/main.rs @@ -1,19 +1,37 @@ use std::cell::RefCell; use std::collections::HashMap; -use we_browser::loader::{ResourceLoader, ABOUT_BLANK_HTML}; +use we_browser::css_loader::collect_stylesheets; +use we_browser::img_loader::{collect_images, ImageStore}; +use we_browser::loader::{Resource, ResourceLoader, ABOUT_BLANK_HTML}; +use we_css::parser::Stylesheet; +use we_dom::{Document, NodeId}; use we_html::parse_html; +use we_image::pixel::Image; use we_layout::layout; use we_platform::appkit; use we_platform::cg::BitmapContext; use we_render::Renderer; -use we_style::computed::{extract_stylesheets, resolve_styles}; +use we_style::computed::resolve_styles; use we_text::font::{self, Font}; +use we_url::Url; + +// --------------------------------------------------------------------------- +// Page state: holds everything needed to re-render without re-fetching +// --------------------------------------------------------------------------- + +/// Pre-fetched page data. Stored so that window resizes only re-style, +/// re-layout, and re-render — no network requests. +struct PageState { + doc: Document, + stylesheet: Stylesheet, + images: ImageStore, +} /// Browser state kept in thread-local storage so the resize handler can /// access it. All AppKit callbacks run on the main thread. struct BrowserState { - html: String, + page: PageState, font: Font, bitmap: Box, view: appkit::BitmapView, @@ -23,36 +41,65 @@ thread_local! { static STATE: RefCell> = const { RefCell::new(None) }; } -/// Re-run the full pipeline: parse → extract CSS → resolve styles → layout → render → copy to bitmap. -fn render_page(html: &str, font: &Font, bitmap: &mut BitmapContext) { +// --------------------------------------------------------------------------- +// Rendering pipeline +// --------------------------------------------------------------------------- + +/// Build a `HashMap` of display dimensions for layout. +fn image_sizes(store: &ImageStore) -> HashMap { + let mut sizes = HashMap::new(); + for (node_id, res) in store { + if res.display_width > 0.0 || res.display_height > 0.0 { + sizes.insert(*node_id, (res.display_width, res.display_height)); + } + } + sizes +} + +/// Build a `HashMap` reference map for the renderer. +fn image_refs(store: &ImageStore) -> HashMap { + let mut refs = HashMap::new(); + for (node_id, res) in store { + if let Some(ref img) = res.image { + refs.insert(*node_id, img); + } + } + refs +} + +/// Re-run the pipeline: resolve styles → layout → render → copy to bitmap. +/// +/// Uses pre-fetched `PageState` so no network I/O happens here. +fn render_page(page: &PageState, font: &Font, bitmap: &mut BitmapContext) { let width = bitmap.width() as u32; let height = bitmap.height() as u32; if width == 0 || height == 0 { return; } - // Parse HTML into DOM. - let doc = parse_html(html); - - // Extract CSS from \ +

Error

{escaped}

" + ); + let base_url = Url::parse("about:blank").expect("about:blank is always valid"); + LoadedHtml { + text: html, + base_url, } } +/// Load a page: fetch HTML, parse DOM, collect CSS and images. +fn load_page(loaded: LoadedHtml) -> PageState { + let doc = parse_html(&loaded.text); + + // Fetch external stylesheets and merge with inline