x-graphics 0.2.1

Graphics framework for X
Documentation
use windows::Win32::Graphics::Direct2D::{
    Common::{D2D_SIZE_F, D2D_SIZE_U},
    ID2D1Bitmap, ID2D1BitmapRenderTarget, ID2D1RenderTarget, D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE,
};

use super::{canvas::D2DCanvas, device::D2DDeviceContext};
use crate::{
    base::Dimension,
    canvas::CanvasBackend,
    error::GraphicsError,
    geometry::{FSize, ISize},
    layer::LayerBackend,
};

const DEFAULT_DPI: f32 = 96.0;

#[derive(Clone, Debug)]
pub struct D2DLayer {
    render_target: ID2D1BitmapRenderTarget,
}

impl Dimension for D2DLayer {
    fn size(&self) -> FSize {
        unsafe { self.render_target.GetSize().into() }
    }

    fn pixel_size(&self) -> ISize {
        let size = unsafe { self.render_target.GetPixelSize() };
        ISize::new(size.width as i32, size.height as i32)
    }
}

impl LayerBackend for D2DLayer {
    type DeviceContextType = D2DDeviceContext;
    type CanvasType = D2DCanvas;

    fn new(_context: Option<&Self::DeviceContextType>, width: usize, height: usize, canvas: &Self::CanvasType) -> Result<Self, GraphicsError> {
        let render_target = canvas.render_target();
        let (mut dpi_x, mut dpi_y) = (0.0, 0.0);
        unsafe {
            render_target.GetDpi(&mut dpi_x, &mut dpi_y);
        }
        let matrix = &canvas.get_matrix().matrix;
        let size = D2D_SIZE_F {
            width: width as f32,
            height: height as f32,
        };
        let pixel_size = D2D_SIZE_U {
            width: (width as f32 * dpi_x * matrix.M11 / DEFAULT_DPI).ceil() as u32,
            height: (height as f32 * dpi_y * matrix.M22 / DEFAULT_DPI).ceil() as u32,
        };
        let render_target = unsafe {
            render_target
                .CreateCompatibleRenderTarget(Some(&size), Some(&pixel_size), None, D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE)
                .map_err(|err| GraphicsError::CreationFailed(err.to_string()))?
        };
        Ok(Self {
            render_target,
        })
    }
}

impl D2DLayer {
    pub(super) fn render_target(&self) -> &ID2D1RenderTarget {
        &self.render_target
    }

    pub(super) fn bitmap(&self) -> Option<ID2D1Bitmap> {
        unsafe { self.render_target.GetBitmap().ok() }
    }
}