Skip to main content

ass_core/analysis/styles/resolved_style/
scaling.rs

1//! Resolution scaling and rendering-complexity computation for `ResolvedStyle`.
2//!
3//! Implements `apply_resolution_scaling` for adjusting coordinate-based
4//! properties and the `calculate_complexity` heuristic used to score rendering
5//! cost.
6
7use super::{ResolvedStyle, TextFormatting};
8
9impl ResolvedStyle<'_> {
10    /// Apply resolution scaling to coordinate-based properties
11    ///
12    /// Scales font size, spacing, outline, shadow, and margins based on the
13    /// resolution difference between layout and play resolutions.
14    ///
15    /// # Arguments
16    ///
17    /// * `scale_x` - Horizontal scaling factor (`PlayResX` / `LayoutResX`)
18    /// * `scale_y` - Vertical scaling factor (`PlayResY` / `LayoutResY`)
19    pub fn apply_resolution_scaling(&mut self, scale_x: f32, scale_y: f32) {
20        // Scale font size (use average of X/Y scaling to maintain aspect ratio)
21        let avg_scale = (scale_x + scale_y) / 2.0;
22        self.font_size *= avg_scale;
23
24        // Scale spacing (horizontal)
25        self.spacing *= scale_x;
26
27        // Scale outline and shadow (use average scaling)
28        self.outline *= avg_scale;
29        self.shadow *= avg_scale;
30
31        // Scale margins
32        #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
33        {
34            self.margin_l = (f32::from(self.margin_l) * scale_x) as u16;
35            self.margin_r = (f32::from(self.margin_r) * scale_x) as u16;
36            self.margin_t = (f32::from(self.margin_t) * scale_y) as u16;
37            self.margin_b = (f32::from(self.margin_b) * scale_y) as u16;
38        }
39
40        // Recalculate complexity score after scaling
41        self.complexity_score = Self::calculate_complexity(self);
42    }
43
44    /// Calculate rendering complexity score
45    pub(super) fn calculate_complexity(style: &Self) -> u8 {
46        const EPSILON: f32 = 0.001;
47        let mut score = 0u8;
48
49        if style.font_size > 72.0 {
50            score += 20;
51        } else if style.font_size > 48.0 {
52            score += 10;
53        }
54
55        if style.outline > 4.0 {
56            score += 15;
57        } else if style.outline > 2.0 {
58            score += 8;
59        }
60
61        if style.shadow > 3.0 {
62            score += 10;
63        } else if style.shadow > 1.0 {
64            score += 5;
65        }
66
67        if (style.scale_x - 100.0).abs() > EPSILON || (style.scale_y - 100.0).abs() > EPSILON {
68            score += 10;
69        }
70
71        if style.angle.abs() > EPSILON {
72            score += 15;
73        }
74
75        if style.formatting.contains(TextFormatting::BOLD) {
76            score += 2;
77        }
78        if style.formatting.contains(TextFormatting::ITALIC) {
79            score += 2;
80        }
81        if style
82            .formatting
83            .intersects(TextFormatting::UNDERLINE | TextFormatting::STRIKE_OUT)
84        {
85            score += 5;
86        }
87
88        score.min(100)
89    }
90}