summaryrefslogtreecommitdiffstats
path: root/wgpu/src/renderer/text.rs
blob: 8fbade4e28e53deb027cb2ceca549718fbd5c041 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use crate::{Primitive, Renderer};
use iced_native::{text, Color, Layout, MouseCursor, Node, Style, Text};

use wgpu_glyph::{GlyphCruncher, Section};

use std::cell::RefCell;
use std::f32;

impl text::Renderer for Renderer {
    fn node(&self, text: &Text) -> Node {
        let glyph_brush = self.glyph_brush.clone();
        let content = text.content.clone();

        // TODO: Investigate why stretch tries to measure this MANY times
        // with every ancestor's bounds.
        // Bug? Using the library wrong? I should probably open an issue on
        // the stretch repository.
        // I noticed that the first measure is the one that matters in
        // practice. Here, we use a RefCell to store the cached measurement.
        let measure = RefCell::new(None);
        let size = text.size.map(f32::from).unwrap_or(20.0);

        let style = Style::default().width(text.width);

        iced_native::Node::with_measure(style, move |bounds| {
            let mut measure = measure.borrow_mut();

            if measure.is_none() {
                let bounds = (
                    match bounds.width {
                        iced_native::Number::Undefined => f32::INFINITY,
                        iced_native::Number::Defined(w) => w,
                    },
                    match bounds.height {
                        iced_native::Number::Undefined => f32::INFINITY,
                        iced_native::Number::Defined(h) => h,
                    },
                );

                let text = Section {
                    text: &content,
                    scale: wgpu_glyph::Scale { x: size, y: size },
                    bounds,
                    ..Default::default()
                };

                let (width, height) = if let Some(bounds) =
                    glyph_brush.borrow_mut().glyph_bounds(&text)
                {
                    (bounds.width(), bounds.height())
                } else {
                    (0.0, 0.0)
                };

                let size = iced_native::Size { width, height };

                // If the text has no width boundary we avoid caching as the
                // layout engine may just be measuring text in a row.
                if bounds.0 == f32::INFINITY {
                    return size;
                } else {
                    *measure = Some(size);
                }
            }

            measure.unwrap()
        })
    }

    fn draw(&mut self, text: &Text, layout: Layout<'_>) -> Self::Output {
        (
            Primitive::Text {
                content: text.content.clone(),
                size: f32::from(text.size.unwrap_or(20)),
                bounds: layout.bounds(),
                color: text.color.unwrap_or(Color::BLACK),
                horizontal_alignment: text.horizontal_alignment,
                vertical_alignment: text.vertical_alignment,
            },
            MouseCursor::OutOfBounds,
        )
    }
}