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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
use std::{
    cell::RefCell,
    rc::Rc,
};

use freya_common::CachedParagraph;
use freya_engine::prelude::*;
use freya_native_core::{
    prelude::NodeType,
    real_dom::NodeImmutable,
};
use freya_node_state::FontStyleState;
use rustc_hash::FxBuildHasher;
use torin::prelude::Size2D;

use super::ParagraphData;
use crate::{
    dom::*,
    render::{
        ParagraphCache,
        ParagraphCacheKey,
        ParagraphCacheText,
    },
};

pub fn create_label(
    node: &DioxusNode,
    area_size: &Size2D,
    font_collection: &FontCollection,
    default_font_family: &[String],
    scale_factor: f32,
    paragraph_cache: &mut ParagraphCache,
) -> ParagraphData {
    let font_style = &*node.get::<FontStyleState>().unwrap();

    let mut label_text = Vec::new();

    for child in node.children() {
        if let NodeType::Text(text) = &*child.node_type() {
            let span_text_hash = FxBuildHasher.hash_one(text);
            label_text.push(span_text_hash);
        }
    }

    let paragraph_cache_key = ParagraphCacheKey::new(
        font_style,
        default_font_family,
        Some(ParagraphCacheText::Hashes(label_text)),
    );

    use std::hash::BuildHasher;

    let hasher = FxBuildHasher;
    let paragraph_cache_key_hash = hasher.hash_one(paragraph_cache_key);

    let paragraph = paragraph_cache.get(&paragraph_cache_key_hash).cloned();

    let paragraph = paragraph.unwrap_or_else(|| {
        let mut paragraph_style = ParagraphStyle::default();
        paragraph_style.set_text_align(font_style.text_align);
        paragraph_style.set_max_lines(font_style.max_lines);
        paragraph_style.set_replace_tab_characters(true);
        paragraph_style.set_text_height_behavior(font_style.text_height);

        if let Some(ellipsis) = font_style.text_overflow.get_ellipsis() {
            paragraph_style.set_ellipsis(ellipsis);
        }

        let text_style =
            font_style.text_style(default_font_family, scale_factor, font_style.text_height);
        paragraph_style.set_text_style(&text_style);

        let mut paragraph_builder = ParagraphBuilder::new(&paragraph_style, font_collection);

        for child in node.children() {
            if let NodeType::Text(text) = &*child.node_type() {
                paragraph_builder.add_text(text);
            }
        }

        CachedParagraph(Rc::new(RefCell::new(paragraph_builder.build())))
    });
    paragraph.0.borrow_mut().layout(
        if font_style.max_lines == Some(1) && font_style.text_align == TextAlign::default() {
            f32::MAX
        } else {
            area_size.width + 1.0
        },
    );

    paragraph_cache.insert(paragraph_cache_key_hash, paragraph.clone());

    let width = match font_style.text_align {
        TextAlign::Start | TextAlign::Left => paragraph.0.borrow().longest_line(),
        _ => paragraph.0.borrow().max_width(),
    };
    let height = paragraph.0.borrow().height();

    ParagraphData {
        size: Size2D::new(width, height),
        paragraph,
    }
}