Skip to content

Commit

Permalink
Merge pull request #597 from Sharktheone/css/infered-size
Browse files Browse the repository at this point in the history
Let images set their own size
  • Loading branch information
Sharktheone authored Sep 13, 2024
2 parents 084cde1 + 27811f5 commit 5a163d1
Show file tree
Hide file tree
Showing 7 changed files with 254 additions and 162 deletions.
14 changes: 13 additions & 1 deletion crates/gosub_render_backend/src/layout.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::fmt::Debug;

use gosub_shared::types::Result;
use gosub_typeface::font::{Font, Glyph};
use std::fmt::Debug;

use crate::geo::{Point, Rect, Size, SizeU32};

Expand Down Expand Up @@ -52,6 +53,17 @@ pub trait Layout: Default {
/// Size of the scroll box (content box without overflow), including scrollbars (if any)
fn size(&self) -> Size;

fn size_or(&self) -> Option<Size>;

fn set_size_and_content(&mut self, size: SizeU32) {
self.set_size(size);
self.set_content(size);
}

fn set_size(&mut self, size: SizeU32);

fn set_content(&mut self, size: SizeU32);

/// Size of the content box (content without scrollbars, but with overflow)
fn content(&self) -> Size;
fn content_box(&self) -> Rect {
Expand Down
69 changes: 55 additions & 14 deletions crates/gosub_renderer/src/draw.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
use std::sync::mpsc::Sender;

use anyhow::anyhow;
use log::warn;
use url::Url;

use crate::debug::scale::px_scale;
use crate::draw::img::request_img;
use crate::render_tree::{load_html_rendertree, TreeDrawer};
use gosub_css3::colors::RgbColor;
use gosub_css3::stylesheet::CssValue;
use gosub_html5::node::NodeId;
Expand All @@ -20,12 +18,15 @@ use gosub_render_backend::{
use gosub_rendering::position::PositionTree;
use gosub_shared::types::Result;
use gosub_styling::render_tree::{RenderNodeData, RenderTree, RenderTreeNode};
use log::warn;

use crate::debug::scale::px_scale;
use crate::draw::img::request_img;
use crate::render_tree::{load_html_rendertree, TreeDrawer};

mod img;

pub trait SceneDrawer<B: RenderBackend, L: Layouter, LT: LayoutTree<L>> {
fn draw(&mut self, backend: &mut B, data: &mut B::WindowData<'_>, size: SizeU32);
fn draw(&mut self, backend: &mut B, data: &mut B::WindowData<'_>, size: SizeU32) -> bool;
fn mouse_move(&mut self, backend: &mut B, x: FP, y: FP) -> bool;

fn scroll(&mut self, point: Point);
Expand All @@ -40,6 +41,8 @@ pub trait SceneDrawer<B: RenderBackend, L: Layouter, LT: LayoutTree<L>> {
fn unselect_element(&mut self);

fn send_nodes(&mut self, sender: Sender<NodeDesc>);

fn set_needs_redraw(&mut self);
}

const DEBUG_CONTENT_COLOR: (u8, u8, u8) = (0, 192, 255); //rgb(0, 192, 255)
Expand All @@ -54,9 +57,9 @@ where
<<B as RenderBackend>::Text as Text>::Font:
From<<<L as Layouter>::TextLayout as TextLayout>::Font>,
{
fn draw(&mut self, backend: &mut B, data: &mut B::WindowData<'_>, size: SizeU32) {
fn draw(&mut self, backend: &mut B, data: &mut B::WindowData<'_>, size: SizeU32) -> bool {
if !self.dirty && self.size == Some(size) {
return;
return false;
}

if self.tree_scene.is_none() || self.size != Some(size) {
Expand Down Expand Up @@ -134,6 +137,14 @@ where

backend.apply_scene(data, &scale, None);
}

if self.dirty {
self.dirty = false;

return true;
}

false
}

fn mouse_move(&mut self, _backend: &mut B, x: FP, y: FP) -> bool {
Expand Down Expand Up @@ -219,6 +230,10 @@ where
fn send_nodes(&mut self, sender: Sender<NodeDesc>) {
let _ = sender.send(self.tree.desc());
}

fn set_needs_redraw(&mut self) {
self.dirty = true;
}
}

struct Drawer<'s, 't, B: RenderBackend, L: Layouter> {
Expand Down Expand Up @@ -267,6 +282,8 @@ where
}

fn render_node(&mut self, id: NodeId, pos: &mut Point) -> anyhow::Result<()> {
let mut needs_redraw = false;

let node = self
.drawer
.tree
Expand All @@ -277,9 +294,11 @@ where
pos.x += p.x as FP;
pos.y += p.y as FP;

let border_radius =
let (border_radius, redraw) =
render_bg::<B, L>(node, self.scene, pos, &mut self.svg, &self.drawer.fetcher);

needs_redraw |= redraw;

if let RenderNodeData::Element(element) = &node.data {
if element.name() == "img" {
let src = element
Expand All @@ -289,21 +308,33 @@ where

let url = src.as_str();

let size = node.layout.size();
let size = node.layout.size_or().map(|x| x.u32());

let img = request_img(&self.drawer.fetcher, &mut self.svg, url, size)?;

let img = request_img(&self.drawer.fetcher, &mut self.svg, url, size.u32())?;
if size.is_none() {
node.layout.set_size_and_content(img.size());
needs_redraw |= true;
}

let fit = element
.attributes
.get("object-fit")
.map(|prop| prop.as_str())
.unwrap_or("contain");

let size = size.unwrap_or(img.size()).f32();

render_image::<B>(img, self.scene, *pos, size, border_radius, fit)?;
}
}

render_text::<B, L>(node, self.scene, pos);

if needs_redraw {
self.drawer.set_needs_redraw()
}

Ok(())
}
}
Expand Down Expand Up @@ -374,7 +405,7 @@ fn render_bg<B: RenderBackend, L: Layouter>(
pos: &Point,
svg: &mut B::SVGRenderer,
fetcher: &Fetcher,
) -> (FP, FP, FP, FP) {
) -> ((FP, FP, FP, FP), bool) {
let bg_color = node
.properties
.get("background-color")
Expand Down Expand Up @@ -485,22 +516,32 @@ fn render_bg<B: RenderBackend, L: Layouter>(
}
});

let mut redraw = false;

if let Some(url) = background_image {
let img = match request_img(fetcher, svg, url, node.layout.size().u32()) {
let size = node.layout.size_or().map(|x| x.u32());

let img = match request_img(fetcher, svg, url, size) {
Ok(img) => img,
Err(e) => {
eprintln!("Error loading image: {:?}", e);
return border_radius;
return (border_radius, false);
}
};

if size.is_none() {
node.layout.set_size_and_content(img.size());

redraw = true;
}

let _ = render_image::<B>(img, scene, *pos, node.layout.size(), border_radius, "fill")
.map_err(|e| {
eprintln!("Error rendering image: {:?}", e);
});
}

border_radius
(border_radius, redraw)
}

enum Side {
Expand Down
12 changes: 9 additions & 3 deletions crates/gosub_renderer/src/draw/img.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
use std::io::Cursor;

use anyhow::anyhow;

use gosub_net::http::fetcher::Fetcher;
use gosub_render_backend::svg::SvgRenderer;
use gosub_render_backend::{Image as _, ImageBuffer, RenderBackend, SizeU32};
use gosub_shared::types::Result;
use std::io::Cursor;

pub fn request_img<B: RenderBackend>(
fetcher: &Fetcher,
svg_renderer: &mut B::SVGRenderer,
url: &str,
size: SizeU32,
size: Option<SizeU32>,
) -> Result<ImageBuffer<B>> {
let res = fetcher.get(url)?;

Expand All @@ -26,7 +28,11 @@ pub fn request_img<B: RenderBackend>(

let svg = <B::SVGRenderer as SvgRenderer<B>>::parse_external(svg)?;

svg_renderer.render_with_size(&svg, size)?
if let Some(size) = size {
svg_renderer.render_with_size(&svg, size)?
} else {
svg_renderer.render(&svg)?
}
} else {
let format = image::guess_format(&img)?;
let img = image::load(Cursor::new(img), format)?; //In that way we don't need to copy the image data
Expand Down
Loading

0 comments on commit 5a163d1

Please sign in to comment.