cranpose-render-pixels 0.1.168

Pixels renderer backend for Cranpose
Documentation
#[cfg(test)]
pub(crate) use cranpose_render_common::graph::quad_bounds;
#[cfg(test)]
pub(crate) use cranpose_render_common::layer_transform::apply_layer_to_rect;
#[cfg(test)]
pub(crate) use cranpose_render_common::layer_transform::{
    apply_layer_affine_to_rect, apply_layer_to_quad,
};
#[cfg(test)]
pub(crate) use cranpose_render_common::style_shared::{
    DrawPlacement, compose_color_filters, primitives_for_placement,
};
pub(crate) use cranpose_render_common::style_shared::{
    apply_layer_to_brush, apply_layer_to_color, combine_layers, scale_corner_radii,
};
#[cfg(test)]
use cranpose_ui::DrawCommand;
#[cfg(test)]
use cranpose_ui_graphics::{BlendMode, DrawPrimitive, GraphicsLayer, ShadowPrimitive, Size};
use cranpose_ui_graphics::{CornerRadii, Rect};

#[cfg(test)]
use crate::scene::RasterScene;

#[cfg(test)]
pub(crate) fn apply_draw_commands(
    commands: &[DrawCommand],
    placement: DrawPlacement,
    rect: Rect,
    size: Size,
    layer: &GraphicsLayer,
    clip: Option<Rect>,
    scene: &mut RasterScene,
) {
    fn emit_primitive(
        primitive: DrawPrimitive,
        layer_bounds: Rect,
        layer: &GraphicsLayer,
        clip: Option<Rect>,
        scene: &mut RasterScene,
        blend_mode: Option<BlendMode>,
    ) {
        match primitive {
            DrawPrimitive::Content => {}
            DrawPrimitive::Blend {
                primitive,
                blend_mode: nested,
            } => emit_primitive(
                *primitive,
                layer_bounds,
                layer,
                clip,
                scene,
                blend_mode.or(Some(nested)),
            ),
            shape_primitive @ (DrawPrimitive::Rect { .. }
            | DrawPrimitive::RoundRect { .. }
            | DrawPrimitive::Arc { .. }
            | DrawPrimitive::Text(_)) => {
                crate::pipeline::push_draw_primitive(
                    &shape_primitive,
                    layer_bounds,
                    layer,
                    clip,
                    scene,
                    blend_mode,
                    false,
                );
            }
            DrawPrimitive::Image {
                rect: local_rect,
                image,
                alpha,
                color_filter,
                sampling,
                src_rect,
            } => {
                let draw_rect = local_rect.translate(layer_bounds.x, layer_bounds.y);
                let local_rect = apply_layer_affine_to_rect(draw_rect, layer_bounds, layer);
                let quad = apply_layer_to_quad(draw_rect, layer_bounds, layer);
                let transformed = quad_bounds(quad);
                let combined_alpha = (alpha * layer.alpha).clamp(0.0, 1.0);
                let combined_filter = compose_color_filters(color_filter, layer.color_filter);
                scene.push_image_with_geometry(
                    transformed,
                    local_rect,
                    quad,
                    image,
                    combined_alpha,
                    combined_filter,
                    sampling,
                    clip,
                    src_rect,
                    blend_mode.unwrap_or(BlendMode::SrcOver),
                );
            }
            DrawPrimitive::Shadow(shadow_primitive) => match shadow_primitive {
                ShadowPrimitive::Drop {
                    shape,
                    cutout,
                    blur_radius: _,
                    blend_mode: shadow_blend_mode,
                } => {
                    emit_primitive(
                        *shape,
                        layer_bounds,
                        layer,
                        clip,
                        scene,
                        blend_mode.or(Some(shadow_blend_mode)),
                    );
                    if let Some(cutout) = cutout {
                        emit_primitive(
                            *cutout,
                            layer_bounds,
                            layer,
                            clip,
                            scene,
                            Some(BlendMode::DstOut),
                        );
                    }
                }
                ShadowPrimitive::Inner {
                    fill,
                    cutout,
                    blur_radius: _,
                    blend_mode: shadow_blend_mode,
                    clip_rect,
                } => {
                    let abs_clip = Rect {
                        x: clip_rect.x + layer_bounds.x,
                        y: clip_rect.y + layer_bounds.y,
                        width: clip_rect.width,
                        height: clip_rect.height,
                    };
                    let transformed_clip = apply_layer_to_rect(abs_clip, layer_bounds, layer);
                    let shadow_clip = clip.map_or(Some(transformed_clip), |parent_clip| {
                        parent_clip.intersect(transformed_clip)
                    });
                    emit_primitive(
                        *fill,
                        layer_bounds,
                        layer,
                        shadow_clip,
                        scene,
                        blend_mode.or(Some(shadow_blend_mode)),
                    );
                    emit_primitive(
                        *cutout,
                        layer_bounds,
                        layer,
                        shadow_clip,
                        scene,
                        blend_mode.or(Some(BlendMode::DstOut)),
                    );
                }
            },
        }
    }

    for command in commands {
        let primitives = primitives_for_placement(command, placement, size);
        for primitive in primitives {
            emit_primitive(primitive, rect, layer, clip, scene, None);
        }
    }
}

pub(crate) fn point_in_resolved_rounded_rect(
    x: f32,
    y: f32,
    rect: Rect,
    radii: &CornerRadii,
) -> bool {
    if !rect.contains(x, y) {
        return false;
    }
    let left = rect.x;
    let right = rect.x + rect.width;
    let top = rect.y;
    let bottom = rect.y + rect.height;

    if radii.top_left > 0.0 && x < left + radii.top_left && y < top + radii.top_left {
        let cx = left + radii.top_left;
        let cy = top + radii.top_left;
        if (x - cx).powi(2) + (y - cy).powi(2) > radii.top_left.powi(2) {
            return false;
        }
    }
    if radii.top_right > 0.0 && x > right - radii.top_right && y < top + radii.top_right {
        let cx = right - radii.top_right;
        let cy = top + radii.top_right;
        if (x - cx).powi(2) + (y - cy).powi(2) > radii.top_right.powi(2) {
            return false;
        }
    }
    if radii.bottom_right > 0.0 && x > right - radii.bottom_right && y > bottom - radii.bottom_right
    {
        let cx = right - radii.bottom_right;
        let cy = bottom - radii.bottom_right;
        if (x - cx).powi(2) + (y - cy).powi(2) > radii.bottom_right.powi(2) {
            return false;
        }
    }
    if radii.bottom_left > 0.0 && x < left + radii.bottom_left && y > bottom - radii.bottom_left {
        let cx = left + radii.bottom_left;
        let cy = bottom - radii.bottom_left;
        if (x - cx).powi(2) + (y - cy).powi(2) > radii.bottom_left.powi(2) {
            return false;
        }
    }
    true
}

#[cfg(test)]
#[path = "tests/style_tests.rs"]
mod tests;