quadraui 0.6.1

Cross-platform Rust UI toolkit: write one AppLogic and run it unmodified on TUI, GTK4 (Linux), macOS, and Windows backends
Documentation
//! Direct2D / DirectWrite rasteriser for
//! [`crate::primitives::diff_view::DiffView`].
//!
//! Painting is shared via [`crate::primitives::diff_view::native_surface_paint::paint`] —
//! see that function's documentation for two named divergences (row/header text vertical
//! alignment; header-label ellipsize vs. hard-clip) found while unifying platform
//! implementations.
//!
//! Only compiled on `target_os = "windows"` — see `super::mod`'s
//! `#[cfg(target_os = "windows")] mod diff_view;` and `backend.rs`'s
//! module docs for why the rest of this repo's `--features win` compile
//! gate stays meaningful without a Windows host.
//!
//! `diff_view_layout` is **not** overridden on `WinBackend` — same as
//! every other backend. It ships a trait default (`Backend::diff_view_layout`)
//! that is a pure function of `line_height()` + `DiffView::mode`, which is
//! exactly what every backend's own `draw_diff_view` already resolves to.
//! The shared [`DiffView::layout`] backs that default's reasoning directly.

#[cfg(test)]
use super::text::DWrite;
#[cfg(test)]
use crate::event::Rect;
#[cfg(test)]
use crate::primitives::diff_view::{DiffView, DiffViewLayout};
#[cfg(test)]
use crate::theme::Theme;

#[cfg(test)]
mod tests {
    use super::*;
    use crate::diff::compute_hunks;
    use crate::primitives::diff_view::{DiffMode, DiffRowKind};
    use crate::types::{Color, WidgetId};
    use crate::win::testing::HeadlessSurface;

    const W: f32 = 400.0;
    const H: f32 = 200.0;
    const LINE_HEIGHT: f32 = 16.0;

    fn sample_view(mode: DiffMode) -> DiffView {
        let left = "one\ntwo\nthree\n";
        let right = "one\nTWO\nthree\n";
        DiffView {
            id: WidgetId::new("diff"),
            left: left.into(),
            right: right.into(),
            left_label: None,
            right_label: None,
            hunks: compute_hunks(left, right),
            mode,
            editability: Default::default(),
            scroll_offset: 0,
            focused_pane: Default::default(),
            has_focus: false,
        }
    }

    fn first_row_of(view: &DiffView, kind: DiffRowKind) -> usize {
        view.hunks
            .iter()
            .flat_map(|h| h.rows.iter())
            .position(|r| r.kind == kind)
            .expect("fixture should contain the requested row kind")
    }

    /// Paint `view` via the shared
    /// [`crate::primitives::diff_view::native_surface_paint::paint`]
    /// through a [`super::super::surface::D2dSurface`] over `surface`'s headless
    /// target — the same adapter the now-removed `draw_diff_view` shim
    /// used, exercised here directly.
    fn paint(
        surface: &HeadlessSurface,
        dwrite: &DWrite,
        rect: Rect,
        view: &DiffView,
        theme: &Theme,
        line_height: f32,
    ) -> DiffViewLayout {
        surface
            .paint(|target| {
                let mut raw = super::super::surface::D2dSurface {
                    target,
                    dwrite: Some(dwrite),
                };
                crate::primitives::diff_view::native_surface_paint::paint(
                    view,
                    &mut raw,
                    theme,
                    rect,
                    line_height,
                );
            })
            .map(|_| view.layout(rect, line_height).as_layout())
            .expect("paint diff view")
    }

    /// `draw_diff_view` must paint text and return a layout usable for scroll clamping.
    #[test]
    fn draw_diff_view_paints_text_and_returns_layout() {
        let surface = HeadlessSurface::new(W as u32, H as u32).expect("create surface");
        let (dwrite, _, _) = DWrite::new("Segoe UI", 10.0, None).expect("create DWrite");
        let theme = Theme {
            background: Color::rgb(255, 255, 255),
            ..Theme::default()
        };
        let view = sample_view(DiffMode::SideBySide);
        let rect = Rect::new(0.0, 0.0, W, H);

        let layout = paint(&surface, &dwrite, rect, &view, &theme, LINE_HEIGHT);

        assert!(layout.visible_rows > 0);
        assert_eq!(layout.total_rows, view.total_rows());

        // "text_ok" — some non-background pixel actually painted inside
        // the left pane (proves DrawText ran, not just the background/row
        // fills).
        let mut painted_any = false;
        for x in 0..(W as u32 / 2) {
            for y in 0..(LINE_HEIGHT as u32 * 3) {
                let px = surface.pixel_at(x, y);
                if (px.r, px.g, px.b) != (255, 255, 255) {
                    painted_any = true;
                }
            }
        }
        assert!(painted_any, "expected diff_view to paint visible glyphs");
    }

    /// The divider colour and position are the same shared geometry every
    /// backend paints from — pins the DIP position independently of the
    /// text-glyph probe above.
    #[test]
    fn divider_paints_border_colour() {
        let surface = HeadlessSurface::new(W as u32, H as u32).expect("create surface");
        let (dwrite, _, _) = DWrite::new("Segoe UI", 10.0, None).expect("create DWrite");
        let theme = Theme::default();
        let view = sample_view(DiffMode::SideBySide);
        let rect = Rect::new(0.0, 0.0, W, H);

        paint(&surface, &dwrite, rect, &view, &theme, LINE_HEIGHT);

        let changed = first_row_of(&view, DiffRowKind::Changed);
        let geometry = view.layout(rect, LINE_HEIGHT);
        let divider_x = geometry.panes.expect("side-by-side has panes").divider_x as u32;
        let row_y = (LINE_HEIGHT * (changed as f32 + 0.5)) as u32;

        let px = surface.pixel_at(divider_x, row_y);
        assert_eq!(
            (px.r, px.g, px.b),
            (theme.border_fg.r, theme.border_fg.g, theme.border_fg.b),
            "the pane divider should be painted in border_fg",
        );
    }

    /// Non-zero-origin regression guard (LESSONS.md — the LOCAL/ABSOLUTE
    /// mixup) — mirrors every other `win::` rasteriser's own nonzero-origin
    /// test (see `win::pipeline_view::paint_and_click_round_trip_action_button_at_nonzero_origin`).
    #[test]
    fn paints_at_a_nonzero_origin_only() {
        let origin_x = 40.0_f32;
        let origin_y = 24.0_f32;
        let surface = HeadlessSurface::new(W as u32, H as u32).expect("create surface");
        let (dwrite, _, _) = DWrite::new("Segoe UI", 10.0, None).expect("create DWrite");
        let theme = Theme::default();
        let view = sample_view(DiffMode::SideBySide);
        let rect = Rect::new(origin_x, origin_y, W - origin_x, H - origin_y);

        // Pre-fill with a sentinel colour distinct from every theme colour
        // this paints with, so "untouched" is unambiguous — mirrors
        // `win::pipeline_view`/`win::list`'s own nonzero-origin tests and
        // this module's own `zero_size_rect_is_a_no_op`. A raw
        // `HeadlessSurface` starts black, which collides with real theme
        // colours closely enough to make a false pass possible.
        surface
            .fill_rect(Rect::new(0.0, 0.0, W, H), Color::rgb(255, 255, 255))
            .expect("fill sentinel background");

        paint(&surface, &dwrite, rect, &view, &theme, LINE_HEIGHT);

        let geometry = view.layout(rect, LINE_HEIGHT);
        let panes = geometry.panes.expect("side-by-side has panes");
        let div_x = panes.divider_x as u32;
        let probe_y = (origin_y + LINE_HEIGHT * 0.5) as u32;

        let px = surface.pixel_at(div_x, probe_y);
        assert_eq!(
            (px.r, px.g, px.b),
            (theme.border_fg.r, theme.border_fg.g, theme.border_fg.b),
            "divider must follow the requested origin",
        );

        // Untouched sentinel above and to the left.
        let above = surface.pixel_at(div_x, origin_y as u32 - 4);
        assert_eq!(
            (above.r, above.g, above.b),
            (255, 255, 255),
            "nothing should paint above the requested origin",
        );
        let left = surface.pixel_at(4, probe_y);
        assert_eq!(
            (left.r, left.g, left.b),
            (255, 255, 255),
            "nothing should paint left of the requested origin",
        );
    }

    /// Unified mode's `total_rows` counts hunk headers too — mirrors the
    /// GTK/macOS/TUI twins' regression guard.
    #[test]
    fn unified_mode_counts_hunk_headers_in_total_rows() {
        let surface = HeadlessSurface::new(W as u32, H as u32).expect("create surface");
        let (dwrite, _, _) = DWrite::new("Segoe UI", 10.0, None).expect("create DWrite");
        let theme = Theme::default();
        let view = sample_view(DiffMode::Unified);
        let rect = Rect::new(0.0, 0.0, W, H);

        let layout = paint(&surface, &dwrite, rect, &view, &theme, LINE_HEIGHT);

        let hunk_count = view.hunks.len();
        assert!(hunk_count > 0, "fixture should produce at least one hunk");
        assert_eq!(
            layout.total_rows,
            view.total_rows() + hunk_count,
            "unified mode reports content rows plus one @@ header per hunk",
        );
    }

    /// No-paint layout must agree with what `draw_diff_view` painted from
    /// — same contract every other `win::` rasteriser's
    /// `no_paint_layout_matches_paint_layout` test proves.
    #[test]
    fn no_paint_layout_matches_paint_layout() {
        let view = sample_view(DiffMode::SideBySide);
        let rect = Rect::new(0.0, 0.0, W, H);
        let (dwrite, _, _) = DWrite::new("Segoe UI", 10.0, None).expect("create DWrite");
        let surface = HeadlessSurface::new(W as u32, H as u32).expect("create surface");
        let theme = Theme::default();

        let painted = paint(&surface, &dwrite, rect, &view, &theme, LINE_HEIGHT);
        let no_paint = view.layout(rect, LINE_HEIGHT).as_layout();
        assert_eq!(painted, no_paint);
    }

    /// Zero-size rect is a no-op — mirrors every other `win::` rasteriser's
    /// same guard.
    #[test]
    fn zero_size_rect_is_a_no_op() {
        let surface = HeadlessSurface::new(W as u32, H as u32).expect("create surface");
        let (dwrite, _, _) = DWrite::new("Segoe UI", 10.0, None).expect("create DWrite");
        let theme = Theme {
            background: Color::rgb(255, 255, 255),
            ..Theme::default()
        };
        let view = sample_view(DiffMode::SideBySide);
        let rect = Rect::new(0.0, 0.0, 0.0, H);

        surface
            .fill_rect(Rect::new(0.0, 0.0, W, H), Color::rgb(255, 255, 255))
            .expect("fill background");

        paint(&surface, &dwrite, rect, &view, &theme, LINE_HEIGHT);

        let px = surface.pixel_at(1, 1);
        assert_eq!(
            (px.r, px.g, px.b),
            (255, 255, 255),
            "a zero-width diff view should paint nothing at all",
        );
    }
}