agg-gui 0.1.1

Immediate-mode Rust GUI library with AGG rendering, Y-up layout, widgets, text, SVG, and native/WASM adapters
Documentation
use super::*;

pub(crate) fn rasterize_linear_gradient_fill(
    fb: &mut Framebuffer,
    path: &mut PathStorage,
    gradient: &LinearGradientPaint,
    global_alpha: f32,
    mode: CompOp,
    clip: Option<(f64, f64, f64, f64)>,
    fill_rule: FillRule,
    transform: &TransAffine,
) {
    rasterize_sampled_fill(
        fb,
        path,
        |x, y| gradient.sample(x, y),
        global_alpha,
        mode,
        clip,
        fill_rule,
        transform,
    );
}

pub(crate) fn rasterize_radial_gradient_fill(
    fb: &mut Framebuffer,
    path: &mut PathStorage,
    gradient: &RadialGradientPaint,
    global_alpha: f32,
    mode: CompOp,
    clip: Option<(f64, f64, f64, f64)>,
    fill_rule: FillRule,
    transform: &TransAffine,
) {
    rasterize_sampled_fill(
        fb,
        path,
        |x, y| gradient.sample(x, y),
        global_alpha,
        mode,
        clip,
        fill_rule,
        transform,
    );
}

pub(crate) fn rasterize_pattern_fill(
    fb: &mut Framebuffer,
    path: &mut PathStorage,
    pattern: &PatternPaint,
    global_alpha: f32,
    mode: CompOp,
    clip: Option<(f64, f64, f64, f64)>,
    fill_rule: FillRule,
    transform: &TransAffine,
) {
    rasterize_sampled_fill(
        fb,
        path,
        |x, y| pattern.sample(x, y),
        global_alpha,
        mode,
        clip,
        fill_rule,
        transform,
    );
}

fn rasterize_sampled_fill<F>(
    fb: &mut Framebuffer,
    path: &mut PathStorage,
    mut sample: F,
    global_alpha: f32,
    _mode: CompOp,
    clip: Option<(f64, f64, f64, f64)>,
    fill_rule: FillRule,
    transform: &TransAffine,
) where
    F: FnMut(f64, f64) -> Color,
{
    let mut mask_fb = Framebuffer::new(fb.width(), fb.height());
    let white = Color::white().to_rgba8();
    rasterize_fill(
        &mut mask_fb,
        path,
        &white,
        CompOp::SrcOver,
        clip,
        fill_rule,
        transform,
    );

    let width = fb.width() as usize;
    let height = fb.height() as usize;
    let mask = mask_fb.pixels();
    let dst = fb.pixels_mut();

    for y in 0..height {
        for x in 0..width {
            let i = (y * width + x) * 4;
            let coverage = mask[i + 3] as f32 / 255.0;
            if coverage <= 0.0 {
                continue;
            }

            let mut lx = x as f64 + 0.5;
            let mut ly = y as f64 + 0.5;
            transform.inverse_transform(&mut lx, &mut ly);
            let mut src = sample(lx, ly);
            src.a *= coverage * global_alpha;

            let sa = src.a.clamp(0.0, 1.0);
            if sa <= 0.0 {
                continue;
            }
            let inv_sa = 1.0 - sa;
            let sr = src.r.clamp(0.0, 1.0) * sa;
            let sg = src.g.clamp(0.0, 1.0) * sa;
            let sb = src.b.clamp(0.0, 1.0) * sa;
            let da = dst[i + 3] as f32 / 255.0;

            dst[i] =
                ((sr + (dst[i] as f32 / 255.0) * inv_sa) * 255.0 + 0.5).clamp(0.0, 255.0) as u8;
            dst[i + 1] =
                ((sg + (dst[i + 1] as f32 / 255.0) * inv_sa) * 255.0 + 0.5).clamp(0.0, 255.0) as u8;
            dst[i + 2] =
                ((sb + (dst[i + 2] as f32 / 255.0) * inv_sa) * 255.0 + 0.5).clamp(0.0, 255.0) as u8;
            dst[i + 3] = ((sa + da * inv_sa) * 255.0 + 0.5).clamp(0.0, 255.0) as u8;
        }
    }
}