StratoSDK is a framework with a declarative approach similar to Flutter/React, written and designed entirely for Rust.
| 1 | pub(crate) mod atlas; |
| 2 | pub(crate) mod glyph_cache; |
| 3 | #[cfg(wgpu)] |
| 4 | pub mod wgpu; |
| 5 | |
| 6 | pub use strato_ui_core::rendering::*; |
| 7 | use strato_ui_core::scene::Dash; |
| 8 | |
| 9 | pub(crate) use glyph_cache::{GlyphCache, GlyphRasterBoundsFn, RasterizeGlyphFn}; |
| 10 | |
| 11 | /// Cache for the result of calling [`is_low_power_gpu_available`], as the |
| 12 | /// check can be expensive. |
| 13 | static LOW_POWER_GPU_AVAILABLE: std::sync::OnceLock<bool> = std::sync::OnceLock::new(); |
| 14 | |
| 15 | /// Returns `true` if a low power GPU is available for rendering. Typically, this is true for |
| 16 | /// machines with two GPUs -- a dedicated discrete high-performance GPU and a lower power |
| 17 | /// integrated GPU. |
| 18 | pub fn is_low_power_gpu_available() -> bool { |
| 19 | *LOW_POWER_GPU_AVAILABLE.get_or_init(|| { |
| 20 | cfg_if::cfg_if! { |
| 21 | if #[cfg(target_os = "macos")] { |
| 22 | crate::platform::mac::is_low_power_gpu_available() |
| 23 | } else if #[cfg(wgpu)] { |
| 24 | strato_ui_core::r#async::block_on(wgpu::is_low_power_gpu_available()) |
| 25 | } else { |
| 26 | false |
| 27 | } |
| 28 | } |
| 29 | }) |
| 30 | } |
| 31 | |
| 32 | /// Returns the gap length between each dash to ensure that the stroke begins and ends with a full dash, |
| 33 | /// minimizing deviation from the target gap length. |
| 34 | // adapted from Blink dashed border rendering code: |
| 35 | // https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:third_party/blink/renderer/platform/graphics/stroke_data.cc;l=130-147;drc=51e1b713f6da38219910bf8fb93a81262340bf97 |
| 36 | pub(crate) fn get_best_dash_gap( |
| 37 | stroke_length: f32, |
| 38 | Dash { |
| 39 | dash_length, |
| 40 | gap_length, |
| 41 | force_consistent_gap_length, |
| 42 | }: Dash, |
| 43 | ) -> f32 { |
| 44 | if force_consistent_gap_length { |
| 45 | return gap_length; |
| 46 | } |
| 47 | |
| 48 | // If no space for two dashes and a gap between, return gap length 0 (solid border) |
| 49 | if stroke_length < 2. * dash_length + gap_length { |
| 50 | return 0.; |
| 51 | } |
| 52 | |
| 53 | let min_num_dashes = (stroke_length / (dash_length + gap_length)).floor(); |
| 54 | let max_num_dashes = min_num_dashes + 1.; |
| 55 | let min_num_gaps = min_num_dashes - 1.; |
| 56 | let max_num_gaps = max_num_dashes - 1.; |
| 57 | let min_gap = (stroke_length - min_num_dashes * dash_length) / min_num_gaps; |
| 58 | let max_gap = (stroke_length - max_num_dashes * dash_length) / max_num_gaps; |
| 59 | if max_gap <= 0. || ((min_gap - gap_length).abs() < (max_gap - gap_length).abs()) { |
| 60 | min_gap |
| 61 | } else { |
| 62 | max_gap |
| 63 | } |
| 64 | } |
| 65 |