mplusfonts-macros 0.3.4

Procedural macros re-exported in the mplusfonts crate
Documentation
mod drawing;
mod metrics;

use std::mem;
use std::mem::MaybeUninit;
use std::ops::IndexMut;

use swash::zeno::Vector;

use crate::mplus::bitmap::color;
use crate::mplus::bitmap::units::Halfwidth;
use crate::mplus::bitmap::{Glyph, Image, ImageList};

pub use drawing::GlyphDrawing;
pub use metrics::GlyphMetrics;

impl GlyphDrawing {
    pub fn scale(&self, positions: u8, bit_depth: u8, glyph_metrics: &GlyphMetrics) -> Vec<Glyph> {
        let advance_width = glyph_metrics.width;
        let is_repeating = glyph_metrics.is_code;
        let mut images = if let Halfwidth::Floor(_) | Halfwidth::Ceil = glyph_metrics.halfwidth {
            let length = if is_repeating { 1 } else { positions };
            let mut images = Vec::new();
            (0..length).for_each(|index| {
                let x_offset = f32::from(index) / f32::from(length);
                let render = self.render;
                let offset = Vector::new(x_offset, 0.0);
                let image_cluster = render(glyph_metrics, offset);
                for (image_index, (data, placement)) in image_cluster.into_iter().enumerate() {
                    if index == 0 {
                        images.push(Vec::from_iter((0..length).map(|_| MaybeUninit::uninit())));
                    }

                    let left = placement.left;
                    let top = glyph_metrics.top as i32 - placement.top;
                    let width = placement.width;
                    let image = Image {
                        left,
                        top,
                        width,
                        data: match data.as_slice() {
                            [] => data,
                            data => color::quantize(data, width, bit_depth),
                        },
                    };

                    images
                        .get_mut(image_index)
                        .expect("exected image index to be less than number of images at `0`")
                        .index_mut(index as usize)
                        .write(image);
                }
            });

            // SAFETY: The full set of images will have been initialized by this point.
            unsafe { mem::transmute::<Vec<Vec<MaybeUninit<Image>>>, Vec<Vec<Image>>>(images) }
        } else {
            Vec::new()
        };

        for images in images.iter_mut() {
            if images.iter().all(|image| image.data.is_empty()) {
                images.clear();
            }
        }

        let mut images = images.into_iter().zip(self.id..);
        let first = images.next().map(|(images, id)| Glyph {
            x_offset: 0.0,
            y_offset: 0.0,
            positions,
            bit_depth,
            id,
            advance_width,
            images: ImageList(images),
        });

        let x_offset = -advance_width;
        let rest = images.map(|(images, id)| Glyph {
            x_offset,
            y_offset: 0.0,
            positions,
            bit_depth,
            id,
            advance_width: 0.0,
            images: ImageList(images),
        });

        first.into_iter().chain(rest).collect()
    }
}