oxidize-html-gpui 0.1.2

GPUI rendering backend for oxidize-html. Translates DrawCommands into GPUI elements.
Documentation
use gpui::{Bounds, ParentElement, Pixels, Styled, div, img, px, rgb};
use oxidize_html::{DrawCommand, Rect};
use std::path::PathBuf;
pub fn command_element(command: &DrawCommand) -> gpui::Div {
    match command {
        DrawCommand::FillRect { rect, color } => abs_rect(*rect).bg(to_gpui_color(*color)),
        DrawCommand::StrokeRect { rect, color, width } => {
            let mut layer = abs_rect(*rect);
            let w = width.max(1.0);
            let top = Rect {
                x: rect.x,
                y: rect.y,
                width: rect.width,
                height: w,
            };
            let right = Rect {
                x: rect.x + rect.width - w,
                y: rect.y,
                width: w,
                height: rect.height,
            };
            let bottom = Rect {
                x: rect.x,
                y: rect.y + rect.height - w,
                width: rect.width,
                height: w,
            };
            let left = Rect {
                x: rect.x,
                y: rect.y,
                width: w,
                height: rect.height,
            };
            for edge in [top, right, bottom, left] {
                layer = layer.child(abs_rect(edge).bg(to_gpui_color(*color)));
            }
            layer
        }
        DrawCommand::DrawText {
            text,
            origin,
            color,
            font_size,
        } => div()
            .absolute()
            .left(px(origin.x))
            .top(px(origin.y))
            .text_size(px(font_size.max(8.0)))
            .text_color(to_gpui_color(*color))
            .child(text.clone()),
        DrawCommand::DrawImagePlaceholder { rect } => abs_rect(*rect).bg(rgb(0xd1d5db)),
        DrawCommand::DrawImage { rect, source } => match source {
            oxidize_html::image::ImageSource::LocalPath(path) => abs_rect(*rect).child(
                img(PathBuf::from(path))
                    .w(px(rect.width.max(1.0)))
                    .h(px(rect.height.max(1.0))),
            ),
            oxidize_html::image::ImageSource::Remote(url) => abs_rect(*rect).child(
                img(url.clone())
                    .w(px(rect.width.max(1.0)))
                    .h(px(rect.height.max(1.0))),
            ),
            _ => abs_rect(*rect).bg(rgb(0xd1d5db)),
        },
        DrawCommand::DrawLine {
            start,
            end,
            color,
            width: _,
        } => {
            let dx = (end.x - start.x).abs();
            let dy = (end.y - start.y).abs();
            if dx >= dy {
                div()
                    .absolute()
                    .left(px(start.x.min(end.x)))
                    .top(px(start.y.min(end.y)))
                    .w(px(dx.max(1.0)))
                    .h(px(1.0))
                    .bg(to_gpui_color(*color))
            } else {
                div()
                    .absolute()
                    .left(px(start.x.min(end.x)))
                    .top(px(start.y.min(end.y)))
                    .w(px(1.0))
                    .h(px(dy.max(1.0)))
                    .bg(to_gpui_color(*color))
            }
        }
        DrawCommand::Link { rect, .. } => abs_rect(Rect {
            x: rect.x,
            y: rect.y + rect.height - 1.0,
            width: rect.width,
            height: 1.0,
        })
        .bg(rgb(0x0a66c2)),
    }
}

fn abs_rect(rect: Rect) -> gpui::Div {
    div()
        .absolute()
        .left(px(rect.x))
        .top(px(rect.y))
        .w(px(rect.width.max(0.0)))
        .h(px(rect.height.max(0.0)))
}

pub fn to_bounds_with_offset(rect: Rect, ox: f32, oy: f32) -> Bounds<Pixels> {
    gpui::bounds(
        gpui::point(px(rect.x + ox), px(rect.y + oy)),
        gpui::size(px(rect.width.max(0.0)), px(rect.height.max(0.0))),
    )
}

pub fn content_extent(commands: &[DrawCommand]) -> (f32, f32) {
    let mut max_x: f32 = 0.0;
    let mut max_y: f32 = 0.0;

    for command in commands {
        match command {
            DrawCommand::FillRect { rect, .. }
            | DrawCommand::StrokeRect { rect, .. }
            | DrawCommand::DrawImagePlaceholder { rect }
            | DrawCommand::DrawImage { rect, .. }
            | DrawCommand::Link { rect, .. } => {
                max_x = max_x.max(rect.x + rect.width);
                max_y = max_y.max(rect.y + rect.height);
            }
            DrawCommand::DrawText {
                text,
                origin,
                font_size,
                ..
            } => {
                let w = (text.chars().count() as f32 * font_size * 0.55).max(*font_size);
                let h = font_size * 1.25;
                max_x = max_x.max(origin.x + w);
                max_y = max_y.max(origin.y + h);
            }
            DrawCommand::DrawLine {
                start, end, width, ..
            } => {
                max_x = max_x.max(start.x.max(end.x) + width);
                max_y = max_y.max(start.y.max(end.y) + width);
            }
        }
    }

    (max_x.max(960.0), max_y.max(720.0))
}

fn to_gpui_color(color: oxidize_html::Rgba) -> gpui::Rgba {
    rgb(((color.r as u32) << 16) | ((color.g as u32) << 8) | color.b as u32)
}