Skip to main content

orinium_browser/engine/bridge/text/
mod.rs

1//! Text measurement abstraction for layout and rendering.
2//!
3//! # Overview
4//!
5//! This module defines the interface between the layout engine and
6//! platform-specific text measurement implementations.
7//!
8//! It does **not** own or define visual text styles.
9//! Instead, it consumes already-resolved text attributes provided
10//! by higher-level layout or rendering layers.
11//!
12//! # Responsibilities
13//!
14//! - Accept text content and layout-related parameters
15//! - Measure intrinsic text size (width, height, baseline)
16//! - Provide a backend-agnostic text measurement abstraction
17//!
18//! # Non-Responsibilities
19//!
20//! - CSS resolution or inheritance
21//! - Interpretation of visual styling semantics
22//! - Rendering or draw command generation
23//!
24//! # Data Flow
25//!
26//! ```text
27//! CSS → Layout → TextMeasurer → TextMetrics
28//! ```
29
30use std::fmt;
31
32/* ============================
33 * Style Type
34 * ============================ */
35
36#[derive(Debug, Clone)]
37pub struct TextAttribute {
38    pub style: TextStyle,
39    pub flow_style: TextFlowStyle,
40}
41
42/* ============================
43 * Measure Request
44 * ============================ */
45
46#[derive(Debug, Clone)]
47pub struct TextMeasureRequest {
48    /// UTF-8 text content
49    pub text: String,
50
51    /// Opaque, resolved text attributes provided by the caller
52    pub attribute: TextAttribute,
53}
54
55/* ============================
56 * Measured Result
57 * ============================ */
58
59/// A measured text fragment produced by [`TextMeasurer::measure_fragments`].
60///
61/// Contains the original text segment along with its measured dimensions,
62/// so callers can both retrieve the split text and obtain fragment widths
63/// for inline layout.
64#[derive(Debug, Clone)]
65pub struct MeasuredFragment {
66    pub text: String,
67    pub width: f32,
68    pub height: f32,
69}
70
71/* ============================
72 * Optional Glyph Info (Future)
73 * ============================ */
74
75#[derive(Debug, Clone)]
76pub struct GlyphMetrics {
77    pub glyph_id: u32,
78    pub x: f32,
79    pub y: f32,
80    pub advance: f32,
81}
82
83/* ============================
84 * Glyph Cluster (for FlowLayouter)
85 * ============================ */
86
87/// A single glyph cluster produced by text shaping.
88///
89/// Carries the cluster's byte offset in the original text, its advance
90/// width, and whether a line break is permitted after it.
91#[derive(Debug, Clone)]
92pub struct GlyphCluster {
93    /// Byte offset of this cluster's first character in the original text.
94    pub byte_offset: usize,
95    /// Advance width in pixels.
96    pub width: f32,
97    /// Whether a line break is permitted immediately after this cluster.
98    pub break_allowed: bool,
99}
100
101/* ============================
102 * Errors
103 * ============================ */
104
105#[derive(Debug)]
106pub enum TextMeasureError {
107    FontUnavailable,
108    UnsupportedScript,
109    LayoutOverflow,
110    Internal(String),
111}
112
113impl fmt::Display for TextMeasureError {
114    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115        match self {
116            Self::FontUnavailable => write!(f, "Font unavailable"),
117            Self::UnsupportedScript => write!(f, "Unsupported script"),
118            Self::LayoutOverflow => write!(f, "Layout overflow"),
119            Self::Internal(s) => write!(f, "Internal error: {s}"),
120        }
121    }
122}
123
124impl std::error::Error for TextMeasureError {}
125
126/* ============================
127 * Trait
128 * ============================ */
129
130pub trait TextMeasurer: Send + Sync {
131    /// Measure a single block of text and return its metrics.
132    fn measure(
133        &self,
134        request: &TextMeasureRequest,
135    ) -> Result<Vec<MeasuredFragment>, TextMeasureError>;
136
137    /// Shape text and return cluster-level break-opportunity data.
138    ///
139    /// Unlike [`measure`](Self::measure), this returns per-cluster
140    /// data suitable for use with [`TextFlowLayouter`].
141    fn measure_shaped(
142        &self,
143        request: &TextMeasureRequest,
144    ) -> Result<Vec<GlyphCluster>, TextMeasureError>;
145}
146
147/* ============================
148 * Fallback
149 * ============================ */
150
151pub mod fallback;
152pub use fallback::FallbackTextMeasurer;
153
154use crate::engine::layouter::types::{TextFlowStyle, TextStyle};