Repository: typst/typst
File: crates/typst-render/src/text.rs (Rust)

Code before:
use std::sync::Arc;

use pixglyph::Bitmap;
use tiny_skia as sk;
use ttf_parser::{GlyphId, OutlineBuilder};
use typst::layout::{Abs, Axes, Point, Size};
use typst::text::color::{glyph_frame, is_outlinable};
use typst::text::{Font, TextItem};
use typst::visualize::{FixedStroke, Paint};

use crate::paint::{self, GradientSampler, PaintSampler, PatternSampler};
use crate::{shape, AbsExt, State};

/// Render a text run into the canvas.
pub fn render_text(canvas: &mut sk::Pixmap, state: State, text: &TextItem) {
    let mut x = 0.0;
    for glyph in &text.glyphs {
        let id = GlyphId(glyph.id);
        let offset = x + glyph.x_offset.at(text.size).to_f32();

        if is_outlinable(&text.font, glyph) {
            let state =
                state.pre_translate(Point::new(Abs::raw(offset as _), Abs::raw(0.0)));
            render_outline_glyph(canvas, state, text, id);
        } else {
            let upem = text.font.units_per_em();
            let text_scale = Abs::raw(text.size.to_raw() / upem);
            let state = state
                .pre_translate(Point::new(Abs::raw(offset as _), -text.size))
                .pre_scale(Axes::new(text_scale, text_scale));

            let (glyph_frame, _) = glyph_frame(&text.font, glyph.id);
            crate::render_frame(canvas, state, &glyph_frame);
        }

        x += glyph.x_advance.at(text.size).to_f32();
    }
}

/// Render an outline glyph into the canvas. This is the "normal" case.
fn render_outline_glyph(
    canvas: &mut sk::Pixmap,
    state: State,
    text: &TextItem,
    id: GlyphId,
) -> Option<()> {

Review comment (suggestion):
Has this been tested on a mac w/ Apple's emoji font?  The copy of Apple Color Emoji I have has mono outlines and color bitmaps.  I suspect this will prefer mono emoji.

Code after:
use std::sync::Arc;

use pixglyph::Bitmap;
use tiny_skia as sk;
use ttf_parser::{GlyphId, OutlineBuilder};
use typst::layout::{Abs, Axes, Point, Size};
use typst::text::color::{glyph_frame, should_outline};
use typst::text::{Font, TextItem};
use typst::visualize::{FixedStroke, Paint};

use crate::paint::{self, GradientSampler, PaintSampler, PatternSampler};
use crate::{shape, AbsExt, State};

/// Render a text run into the canvas.
pub fn render_text(canvas: &mut sk::Pixmap, state: State, text: &TextItem) {
    let mut x = 0.0;
    for glyph in &text.glyphs {
        let id = GlyphId(glyph.id);
        let offset = x + glyph.x_offset.at(text.size).to_f32();

        if should_outline(&text.font, glyph) {
            let state =
                state.pre_translate(Point::new(Abs::raw(offset as _), Abs::raw(0.0)));
            render_outline_glyph(canvas, state, text, id);
        } else {
            let upem = text.font.units_per_em();
            let text_scale = Abs::raw(text.size.to_raw() / upem);
            let state = state
                .pre_translate(Point::new(Abs::raw(offset as _), -text.size))
                .pre_scale(Axes::new(text_scale, text_scale));

            let (glyph_frame, _) = glyph_frame(&text.font, glyph.id);
            crate::render_frame(canvas, state, &glyph_frame);
        }

        x += glyph.x_advance.at(text.size).to_f32();
    }
}

/// Render an outline glyph into the canvas. This is the "normal" case.
fn render_outline_glyph(
    canvas: &mut sk::Pixmap,
    state: State,
    text: &TextItem,
    id: GlyphId,
) -> Option<()> {