inset_embedder/caption_style.rs
1//! The user's caption style: how the system's settings say subtitles and captions are to look,
2//! read beside the cues a player hands out, which carry the media's own styling alone ([`Cue`]).
3//! The systems that keep caption settings give the same ones, and tell when the user changes
4//! them: Apple's `MACaptionAppearance`, Android's `CaptioningManager` with its `CaptionStyle`, and
5//! Windows' `ClosedCaptionProperties`, which Chromium's `ui/native_theme/caption_style` reads on
6//! Windows and macOS. Linux and the web keep none, and a platform there answers no
7//! [`CaptionSettings`].
8//!
9//! Each setting says whether it applies always, over what the media says, or only where the media
10//! says nothing, as Apple's `MACaptionAppearanceBehavior` says of each of its settings: Chromium's
11//! and WebKit's cue style sheets make the first `!important` and leave the second for the media's
12//! own style to override. A setting the system gives no value for is `None`, as Android's
13//! `hasForegroundColor` false and Windows' `Default` say.
14//!
15//! The app merges the style into each cue as it draws it, as Media3's `SubtitleView` applies its
16//! `CaptionStyleCompat`; the host merges nothing.
17//!
18//! [`Cue`]: crate::Cue
19
20use crate::{Color, CueTextEdge, MediaChangeFuture};
21
22/// The user's system-wide caption settings: Apple's `MACaptionAppearance`, Android's
23/// `CaptioningManager`, Windows' `ClosedCaptionProperties`.
24pub trait CaptionSettings {
25 /// The style the user set, each setting saying whether it applies always or only where the
26 /// media says nothing.
27 fn style(&self) -> CaptionStyle;
28
29 /// Resolves at the next change of the style, as a player's `changed()` does.
30 fn changed(&self) -> MediaChangeFuture;
31}
32
33/// What the system's settings say of how subtitles and captions look.
34#[derive(Clone, Debug, Default, PartialEq)]
35pub struct CaptionStyle {
36 /// The text's colour, opaque: Apple's foreground colour, Android's `foregroundColor`,
37 /// Windows' `FontColor`.
38 pub foreground_color: Option<CaptionSetting<Color>>,
39 /// The text's opacity, from `0.0` to `1.0`: Apple's foreground opacity, the alpha of Android's
40 /// `foregroundColor`, Windows' `FontOpacity`.
41 pub foreground_opacity: Option<CaptionSetting<f64>>,
42 /// The colour behind each character, opaque: Apple's background colour, Android's
43 /// `backgroundColor`, Windows' `BackgroundColor`.
44 pub background_color: Option<CaptionSetting<Color>>,
45 /// The opacity behind each character: Apple's background opacity, the alpha of Android's
46 /// `backgroundColor`, Windows' `BackgroundOpacity`.
47 pub background_opacity: Option<CaptionSetting<f64>>,
48 /// The colour of the box behind a whole cue, opaque: Apple's window colour, Android's
49 /// `windowColor`, Windows' `RegionColor`.
50 pub window_color: Option<CaptionSetting<Color>>,
51 /// The opacity of the box behind a whole cue: Apple's window opacity, the alpha of Android's
52 /// `windowColor`, Windows' `RegionOpacity`.
53 pub window_opacity: Option<CaptionSetting<f64>>,
54 /// The radius the box's corners are rounded by, in logical pixels: Apple's window rounded
55 /// corner radius, which Chromium and WebKit read as the cue's `border-radius`.
56 pub window_corner_radius: Option<CaptionSetting<f64>>,
57 /// What is drawn round the characters: Apple's text edge style, Android's `edgeType`, Windows'
58 /// `FontEffect`.
59 pub edge: Option<CaptionSetting<CueTextEdge>>,
60 /// The colour of the edge, with its opacity: Android's `edgeColor`. Apple and Windows give
61 /// none.
62 pub edge_color: Option<CaptionSetting<Color>>,
63 /// The font: Apple's font for its default style, Android's typeface, Windows' `FontStyle`.
64 pub typeface: Option<CaptionSetting<CaptionTypeface>>,
65 /// How many times its own size text is drawn at: Apple's relative character size, Android's
66 /// `getFontScale`, Windows' `FontSize` as a fraction.
67 pub text_scale: Option<CaptionSetting<f64>>,
68}
69
70/// One of the user's caption settings, and whether it applies over what the media says.
71#[derive(Clone, Copy, Debug, PartialEq, Eq)]
72pub struct CaptionSetting<T> {
73 pub value: T,
74 pub behavior: CaptionBehavior,
75}
76
77impl<T> CaptionSetting<T> {
78 /// `value`, applied over what the media says.
79 pub fn always(value: T) -> CaptionSetting<T> {
80 CaptionSetting {
81 value,
82 behavior: CaptionBehavior::Always,
83 }
84 }
85
86 /// `value`, applied where the media says nothing.
87 pub fn where_media_says_nothing(value: T) -> CaptionSetting<T> {
88 CaptionSetting {
89 value,
90 behavior: CaptionBehavior::WhereMediaSaysNothing,
91 }
92 }
93}
94
95/// When a caption setting applies: Apple's `MACaptionAppearanceBehavior`.
96#[derive(Clone, Copy, Debug, PartialEq, Eq)]
97pub enum CaptionBehavior {
98 /// Over what the media says: Apple's `UseValue`, a setting Chromium's and WebKit's cue style
99 /// sheets mark `!important`.
100 Always,
101 /// Only where the media says nothing: Apple's `UseContentIfAvailable`, and every setting of
102 /// Android's, which Media3 draws beneath a cue's embedded styles.
103 WhereMediaSaysNothing,
104}
105
106/// The font captions are drawn in.
107#[derive(Clone, Debug, PartialEq, Eq)]
108pub enum CaptionTypeface {
109 /// A font family by name: the family of the font Apple's settings give for their default
110 /// style, or Android's typeface by its family name, such as `serif-monospace`.
111 Family(String),
112 /// A kind of font, as caption standards (CEA-708) name them and Windows gives the user's
113 /// choice.
114 Generic(GenericCaptionFont),
115}
116
117/// The kinds of font caption standards name: Windows' `ClosedCaptionStyle` and Apple's
118/// `MACaptionAppearanceFontStyle`, their defaults aside.
119#[derive(Clone, Copy, Debug, PartialEq, Eq)]
120pub enum GenericCaptionFont {
121 MonospacedWithSerifs,
122 ProportionalWithSerifs,
123 MonospacedWithoutSerifs,
124 ProportionalWithoutSerifs,
125 Casual,
126 Cursive,
127 SmallCapitals,
128}