Skip to content

Commit 5fede3a

Browse files
SkajdrowskiCryZe
andauthored
Initial drop shadow support (#863)
Co-authored-by: Christopher Serr <[email protected]>
1 parent 4ee19e0 commit 5fede3a

File tree

15 files changed

+204
-60
lines changed

15 files changed

+204
-60
lines changed

capi/src/server_protocol.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ pub struct ServerProtocol {}
1919
impl ServerProtocol {
2020
/// Handles an incoming command and returns the response to be sent.
2121
pub async unsafe fn handleCommand(command: &str, commandSink: *const CommandSink) -> String {
22-
server_protocol::handle_command(command, &*commandSink).await
22+
// SAFETY: The caller must ensure that the pointer is valid.
23+
server_protocol::handle_command(command, unsafe { &*commandSink }).await
2324
}
2425

2526
/// Encodes an event that happened to be sent.

capi/src/web_rendering.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ impl WebRenderer {
4141
state: *const LayoutState,
4242
image_cache: *const ImageCache,
4343
) -> Option<Box<[f32]>> {
44-
self.inner.render(&*state, &*image_cache).map(Box::from)
44+
// SAFETY: The caller must ensure that the pointers are valid.
45+
unsafe {
46+
self.inner.render(&*state, &*image_cache).map(Box::from)
47+
}
4548
}
4649
}

src/layout/general_settings.rs

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ pub struct GeneralSettings {
2222
/// The font to use for regular text. `None` means a default font should be
2323
/// used.
2424
pub text_font: Option<Font>,
25+
/// The color to use for drawn shadows.
26+
pub text_shadow: Option<Color>,
2527
/// The background to show behind the layout.
2628
pub background: LayoutBackground,
2729
/// The color to use for when the runner achieved a best segment.
@@ -59,6 +61,7 @@ impl Default for GeneralSettings {
5961
timer_font: None,
6062
times_font: None,
6163
text_font: None,
64+
text_shadow: Some(Color::hsla(0.0, 0.0, 0.0, 0.5)),
6265
background: LayoutBackground::Gradient(Gradient::Plain(Color::hsla(
6366
0.0, 0.0, 0.06, 1.0,
6467
))),
@@ -109,6 +112,11 @@ impl GeneralSettings {
109112
.into(),
110113
self.text_font.clone().into(),
111114
),
115+
Field::new(
116+
"Text Shadow".into(),
117+
"Allows you to optionally specify a color for text shadows.".into(),
118+
self.text_shadow.into(),
119+
),
112120
Field::new(
113121
"Background".into(),
114122
"The background shown behind the entire layout.".into(),
@@ -189,18 +197,19 @@ impl GeneralSettings {
189197
1 => self.timer_font = value.into(),
190198
2 => self.times_font = value.into(),
191199
3 => self.text_font = value.into(),
192-
4 => self.background = LayoutBackground::from(value).from_cache(image_cache),
193-
5 => self.best_segment_color = value.into(),
194-
6 => self.ahead_gaining_time_color = value.into(),
195-
7 => self.ahead_losing_time_color = value.into(),
196-
8 => self.behind_gaining_time_color = value.into(),
197-
9 => self.behind_losing_time_color = value.into(),
198-
10 => self.not_running_color = value.into(),
199-
11 => self.personal_best_color = value.into(),
200-
12 => self.paused_color = value.into(),
201-
13 => self.thin_separators_color = value.into(),
202-
14 => self.separators_color = value.into(),
203-
15 => self.text_color = value.into(),
200+
4 => self.text_shadow = value.into(),
201+
5 => self.background = LayoutBackground::from(value).from_cache(image_cache),
202+
6 => self.best_segment_color = value.into(),
203+
7 => self.ahead_gaining_time_color = value.into(),
204+
8 => self.ahead_losing_time_color = value.into(),
205+
9 => self.behind_gaining_time_color = value.into(),
206+
10 => self.behind_losing_time_color = value.into(),
207+
11 => self.not_running_color = value.into(),
208+
12 => self.personal_best_color = value.into(),
209+
13 => self.paused_color = value.into(),
210+
14 => self.thin_separators_color = value.into(),
211+
15 => self.separators_color = value.into(),
212+
16 => self.text_color = value.into(),
204213
_ => panic!("Unsupported Setting Index"),
205214
}
206215
}

src/layout/layout_state.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ pub struct LayoutState {
2222
/// The font to use for regular text. `None` means a default font should be
2323
/// used.
2424
pub text_font: Option<Font>,
25+
/// An optional text shadow color.
26+
pub text_shadow: Option<Color>,
2527
/// The background to show behind the layout.
2628
pub background: LayoutBackground<ImageId>,
2729
/// The color of thin separators.

src/layout/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ impl Layout {
119119
state.separators_color = settings.separators_color;
120120
state.text_color = settings.text_color;
121121
state.direction = settings.direction;
122+
state.text_shadow = settings.text_shadow;
122123
}
123124

124125
/// Calculates the layout's state based on the timer provided. You can use

src/layout/parser/mod.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use super::{Component, Layout, LayoutDirection};
44
use crate::{
55
component::{separator, timer::DeltaGradient},
6-
platform::{math::f32::powf, prelude::*},
6+
platform::{math::f32::stable_powf, prelude::*},
77
settings::{
88
Alignment, BackgroundImage, Color, Font, FontStretch, FontStyle, FontWeight, Gradient,
99
Image, LayoutBackground, ListGradient,
@@ -321,8 +321,8 @@ where
321321
// black. Because of that, we use 1.75 as the exponent denominator for
322322
// the white on black case instead of the usual 2.2 for sRGB.
323323
let lightness = (r + g + b) * (1.0 / 3.0);
324-
color.alpha =
325-
(1.0 - lightness) * (1.0 - powf(1.0 - a, 1.0 / 2.2)) + lightness * powf(a, 1.0 / 1.75);
324+
color.alpha = (1.0 - lightness) * (1.0 - stable_powf(1.0 - a, 1.0 / 2.2))
325+
+ lightness * stable_powf(a, 1.0 / 1.75);
326326

327327
func(color);
328328
Ok(())
@@ -708,6 +708,8 @@ fn parse_general_settings(layout: &mut Layout, reader: &mut Reader<'_>) -> Resul
708708
let mut background_image = None;
709709
let mut image_opacity = 1.0;
710710
let mut image_blur = 0.0;
711+
let mut has_text_shadow = false;
712+
let mut text_shadow_color = Color::transparent();
711713

712714
parse_children(reader, |reader, tag, _| match tag.name() {
713715
"TextColor" => color(reader, |color| {
@@ -779,9 +781,13 @@ fn parse_general_settings(layout: &mut Layout, reader: &mut Reader<'_>) -> Resul
779781
}),
780782
"ImageOpacity" => percentage(reader, |v| image_opacity = v),
781783
"ImageBlur" => percentage(reader, |v| image_blur = v),
784+
"DropShadows" => parse_bool(reader, |b| has_text_shadow = b),
785+
"ShadowsColor" => color(reader, |color| text_shadow_color = color),
782786
_ => end_tag(reader),
783787
})?;
784788

789+
settings.text_shadow = has_text_shadow.then_some(text_shadow_color);
790+
785791
settings.background = match background_builder.build() {
786792
Some(gradient) => LayoutBackground::Gradient(gradient),
787793
None => match background_image {

src/platform/math.rs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,37 @@
1-
cfg_if::cfg_if! {
2-
if #[cfg(all(feature = "std", not(test)))] {
3-
pub mod f32 {
1+
pub mod f32 {
2+
cfg_if::cfg_if! {
3+
if #[cfg(all(feature = "std"))] {
44
#[inline(always)]
55
#[allow(clippy::missing_const_for_fn)] // Can't do this for the libm counterpart.
66
pub fn abs(x: f32) -> f32 {
77
x.abs()
88
}
9+
} else {
10+
pub use libm::fabsf as abs;
11+
}
12+
}
913

14+
// FIXME: For our tests we need to ensure that the `powf` function behaves
15+
// consistently across all platforms. Ideally we would only use it during
16+
// testing, but cfg(test) apparently doesn't work for integration tests. We
17+
// ensure consistent results by increasing the precision for the powf by
18+
// using f64 internally.
19+
#[inline(always)]
20+
pub fn stable_powf(x: f32, y: f32) -> f32 {
21+
super::f64::powf(x as f64, y as f64) as f32
22+
}
23+
}
24+
25+
mod f64 {
26+
cfg_if::cfg_if! {
27+
if #[cfg(all(feature = "std"))] {
1028
#[inline(always)]
11-
pub fn powf(x: f32, y: f32) -> f32 {
29+
#[allow(clippy::missing_const_for_fn)] // Can't do this for the libm counterpart.
30+
pub fn powf(x: f64, y: f64) -> f64 {
1231
x.powf(y)
1332
}
14-
}
15-
} else {
16-
pub mod f32 {
17-
pub use libm::{fabsf as abs, powf};
33+
} else {
34+
pub use libm::pow as powf;
1835
}
1936
}
2037
}

src/rendering/component/detailed_timer.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ use crate::{
22
component::detailed_timer::State,
33
layout::LayoutState,
44
rendering::{
5+
RenderContext,
56
component::timer,
6-
consts::{vertical_padding, BOTH_PADDINGS, PADDING},
7+
consts::{BOTH_PADDINGS, PADDING, vertical_padding},
78
font::CachedLabel,
89
resource::ResourceAllocator,
910
scene::Layer,
10-
solid, RenderContext,
11+
solid,
1112
},
1213
};
1314

src/rendering/component/key_value.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ use crate::{
22
component::key_value::State,
33
layout::{LayoutDirection, LayoutState},
44
rendering::{
5+
RenderContext,
56
font::{AbbreviatedLabel, CachedLabel},
67
resource::ResourceAllocator,
7-
RenderContext,
88
},
99
};
1010

@@ -30,6 +30,7 @@ pub(in crate::rendering) fn render<A: ResourceAllocator>(
3030
layout_state: &LayoutState,
3131
) {
3232
context.render_background(dim, &component.background);
33+
3334
context.render_key_value_component(
3435
&component.key,
3536
&component.key_abbreviations,

src/rendering/component/text.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ use crate::{
22
component::text::{State, TextState},
33
layout::{LayoutDirection, LayoutState},
44
rendering::{
5+
RenderContext,
56
consts::{DEFAULT_TEXT_SIZE, PADDING, TEXT_ALIGN_TOP},
67
font::{AbbreviatedLabel, CachedLabel},
78
resource::ResourceAllocator,
8-
solid, RenderContext,
9+
solid,
910
},
1011
};
1112

@@ -31,6 +32,7 @@ pub(in crate::rendering) fn render<A: ResourceAllocator>(
3132
layout_state: &LayoutState,
3233
) {
3334
context.render_background([width, height], &component.background);
35+
3436
match &component.text {
3537
TextState::Center(text) => context.render_text_centered(
3638
text,

0 commit comments

Comments
 (0)