summaryrefslogtreecommitdiffstats
path: root/tiny_skia/src/backend.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tiny_skia/src/backend.rs')
-rw-r--r--tiny_skia/src/backend.rs1033
1 files changed, 0 insertions, 1033 deletions
diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs
deleted file mode 100644
index d0f28876..00000000
--- a/tiny_skia/src/backend.rs
+++ /dev/null
@@ -1,1033 +0,0 @@
-use crate::core::{
- Background, Color, Gradient, Rectangle, Size, Transformation, Vector,
-};
-use crate::graphics::backend;
-use crate::graphics::text;
-use crate::graphics::{Damage, Viewport};
-use crate::primitive::{self, Primitive};
-use crate::window;
-
-use std::borrow::Cow;
-
-#[derive(Debug)]
-pub struct Backend {
- text_pipeline: crate::text::Pipeline,
-
- #[cfg(feature = "image")]
- raster_pipeline: crate::raster::Pipeline,
-
- #[cfg(feature = "svg")]
- vector_pipeline: crate::vector::Pipeline,
-}
-
-impl Backend {
- pub fn new() -> Self {
- Self {
- text_pipeline: crate::text::Pipeline::new(),
-
- #[cfg(feature = "image")]
- raster_pipeline: crate::raster::Pipeline::new(),
-
- #[cfg(feature = "svg")]
- vector_pipeline: crate::vector::Pipeline::new(),
- }
- }
-
- pub fn draw<T: AsRef<str>>(
- &mut self,
- pixels: &mut tiny_skia::PixmapMut<'_>,
- clip_mask: &mut tiny_skia::Mask,
- primitives: &[Primitive],
- viewport: &Viewport,
- damage: &[Rectangle],
- background_color: Color,
- overlay: &[T],
- ) {
- let physical_size = viewport.physical_size();
- let scale_factor = viewport.scale_factor() as f32;
-
- if !overlay.is_empty() {
- let path = tiny_skia::PathBuilder::from_rect(
- tiny_skia::Rect::from_xywh(
- 0.0,
- 0.0,
- physical_size.width as f32,
- physical_size.height as f32,
- )
- .expect("Create damage rectangle"),
- );
-
- pixels.fill_path(
- &path,
- &tiny_skia::Paint {
- shader: tiny_skia::Shader::SolidColor(into_color(Color {
- a: 0.1,
- ..background_color
- })),
- anti_alias: false,
- ..Default::default()
- },
- tiny_skia::FillRule::default(),
- tiny_skia::Transform::identity(),
- None,
- );
- }
-
- for &region in damage {
- let path = tiny_skia::PathBuilder::from_rect(
- tiny_skia::Rect::from_xywh(
- region.x,
- region.y,
- region.width,
- region.height,
- )
- .expect("Create damage rectangle"),
- );
-
- pixels.fill_path(
- &path,
- &tiny_skia::Paint {
- shader: tiny_skia::Shader::SolidColor(into_color(
- background_color,
- )),
- anti_alias: false,
- blend_mode: tiny_skia::BlendMode::Source,
- ..Default::default()
- },
- tiny_skia::FillRule::default(),
- tiny_skia::Transform::identity(),
- None,
- );
-
- adjust_clip_mask(clip_mask, region);
-
- for primitive in primitives {
- self.draw_primitive(
- primitive,
- pixels,
- clip_mask,
- region,
- scale_factor,
- Transformation::IDENTITY,
- );
- }
-
- if !overlay.is_empty() {
- pixels.stroke_path(
- &path,
- &tiny_skia::Paint {
- shader: tiny_skia::Shader::SolidColor(into_color(
- Color::from_rgb(1.0, 0.0, 0.0),
- )),
- anti_alias: false,
- ..tiny_skia::Paint::default()
- },
- &tiny_skia::Stroke {
- width: 1.0,
- ..tiny_skia::Stroke::default()
- },
- tiny_skia::Transform::identity(),
- None,
- );
- }
- }
-
- self.text_pipeline.trim_cache();
-
- #[cfg(feature = "image")]
- self.raster_pipeline.trim_cache();
-
- #[cfg(feature = "svg")]
- self.vector_pipeline.trim_cache();
- }
-
- fn draw_primitive(
- &mut self,
- primitive: &Primitive,
- pixels: &mut tiny_skia::PixmapMut<'_>,
- clip_mask: &mut tiny_skia::Mask,
- clip_bounds: Rectangle,
- scale_factor: f32,
- transformation: Transformation,
- ) {
- match primitive {
- Primitive::Quad {
- bounds,
- background,
- border,
- shadow,
- } => {
- debug_assert!(
- bounds.width.is_normal(),
- "Quad with non-normal width!"
- );
- debug_assert!(
- bounds.height.is_normal(),
- "Quad with non-normal height!"
- );
-
- let physical_bounds = (*bounds * transformation) * scale_factor;
-
- if !clip_bounds.intersects(&physical_bounds) {
- return;
- }
-
- let clip_mask = (!physical_bounds.is_within(&clip_bounds))
- .then_some(clip_mask as &_);
-
- let transform = into_transform(transformation)
- .post_scale(scale_factor, scale_factor);
-
- // Make sure the border radius is not larger than the bounds
- let border_width = border
- .width
- .min(bounds.width / 2.0)
- .min(bounds.height / 2.0);
-
- let mut fill_border_radius = <[f32; 4]>::from(border.radius);
- for radius in &mut fill_border_radius {
- *radius = (*radius)
- .min(bounds.width / 2.0)
- .min(bounds.height / 2.0);
- }
- let path = rounded_rectangle(*bounds, fill_border_radius);
-
- if shadow.color.a > 0.0 {
- let shadow_bounds = (Rectangle {
- x: bounds.x + shadow.offset.x - shadow.blur_radius,
- y: bounds.y + shadow.offset.y - shadow.blur_radius,
- width: bounds.width + shadow.blur_radius * 2.0,
- height: bounds.height + shadow.blur_radius * 2.0,
- } * transformation)
- * scale_factor;
-
- let radii = fill_border_radius
- .into_iter()
- .map(|radius| radius * scale_factor)
- .collect::<Vec<_>>();
- let (x, y, width, height) = (
- shadow_bounds.x as u32,
- shadow_bounds.y as u32,
- shadow_bounds.width as u32,
- shadow_bounds.height as u32,
- );
- let half_width = physical_bounds.width / 2.0;
- let half_height = physical_bounds.height / 2.0;
-
- let colors = (y..y + height)
- .flat_map(|y| {
- (x..x + width).map(move |x| (x as f32, y as f32))
- })
- .filter_map(|(x, y)| {
- tiny_skia::Size::from_wh(half_width, half_height)
- .map(|size| {
- let shadow_distance = rounded_box_sdf(
- Vector::new(
- x - physical_bounds.position().x
- - (shadow.offset.x
- * scale_factor)
- - half_width,
- y - physical_bounds.position().y
- - (shadow.offset.y
- * scale_factor)
- - half_height,
- ),
- size,
- &radii,
- )
- .max(0.0);
- let shadow_alpha = 1.0
- - smoothstep(
- -shadow.blur_radius * scale_factor,
- shadow.blur_radius * scale_factor,
- shadow_distance,
- );
-
- let mut color = into_color(shadow.color);
- color.apply_opacity(shadow_alpha);
-
- color.to_color_u8().premultiply()
- })
- })
- .collect();
-
- if let Some(pixmap) = tiny_skia::IntSize::from_wh(
- width, height,
- )
- .and_then(|size| {
- tiny_skia::Pixmap::from_vec(
- bytemuck::cast_vec(colors),
- size,
- )
- }) {
- pixels.draw_pixmap(
- x as i32,
- y as i32,
- pixmap.as_ref(),
- &tiny_skia::PixmapPaint::default(),
- tiny_skia::Transform::default(),
- None,
- );
- }
- }
-
- pixels.fill_path(
- &path,
- &tiny_skia::Paint {
- shader: match background {
- Background::Color(color) => {
- tiny_skia::Shader::SolidColor(into_color(
- *color,
- ))
- }
- Background::Gradient(Gradient::Linear(linear)) => {
- let (start, end) =
- linear.angle.to_distance(bounds);
-
- let stops: Vec<tiny_skia::GradientStop> =
- linear
- .stops
- .into_iter()
- .flatten()
- .map(|stop| {
- tiny_skia::GradientStop::new(
- stop.offset,
- tiny_skia::Color::from_rgba(
- stop.color.b,
- stop.color.g,
- stop.color.r,
- stop.color.a,
- )
- .expect("Create color"),
- )
- })
- .collect();
-
- tiny_skia::LinearGradient::new(
- tiny_skia::Point {
- x: start.x,
- y: start.y,
- },
- tiny_skia::Point { x: end.x, y: end.y },
- if stops.is_empty() {
- vec![tiny_skia::GradientStop::new(
- 0.0,
- tiny_skia::Color::BLACK,
- )]
- } else {
- stops
- },
- tiny_skia::SpreadMode::Pad,
- tiny_skia::Transform::identity(),
- )
- .expect("Create linear gradient")
- }
- },
- anti_alias: true,
- ..tiny_skia::Paint::default()
- },
- tiny_skia::FillRule::EvenOdd,
- transform,
- clip_mask,
- );
-
- if border_width > 0.0 {
- // Border path is offset by half the border width
- let border_bounds = Rectangle {
- x: bounds.x + border_width / 2.0,
- y: bounds.y + border_width / 2.0,
- width: bounds.width - border_width,
- height: bounds.height - border_width,
- };
-
- // Make sure the border radius is correct
- let mut border_radius = <[f32; 4]>::from(border.radius);
- let mut is_simple_border = true;
-
- for radius in &mut border_radius {
- *radius = if *radius == 0.0 {
- // Path should handle this fine
- 0.0
- } else if *radius > border_width / 2.0 {
- *radius - border_width / 2.0
- } else {
- is_simple_border = false;
- 0.0
- }
- .min(border_bounds.width / 2.0)
- .min(border_bounds.height / 2.0);
- }
-
- // Stroking a path works well in this case
- if is_simple_border {
- let border_path =
- rounded_rectangle(border_bounds, border_radius);
-
- pixels.stroke_path(
- &border_path,
- &tiny_skia::Paint {
- shader: tiny_skia::Shader::SolidColor(
- into_color(border.color),
- ),
- anti_alias: true,
- ..tiny_skia::Paint::default()
- },
- &tiny_skia::Stroke {
- width: border_width,
- ..tiny_skia::Stroke::default()
- },
- transform,
- clip_mask,
- );
- } else {
- // Draw corners that have too small border radii as having no border radius,
- // but mask them with the rounded rectangle with the correct border radius.
- let mut temp_pixmap = tiny_skia::Pixmap::new(
- bounds.width as u32,
- bounds.height as u32,
- )
- .unwrap();
-
- let mut quad_mask = tiny_skia::Mask::new(
- bounds.width as u32,
- bounds.height as u32,
- )
- .unwrap();
-
- let zero_bounds = Rectangle {
- x: 0.0,
- y: 0.0,
- width: bounds.width,
- height: bounds.height,
- };
- let path =
- rounded_rectangle(zero_bounds, fill_border_radius);
-
- quad_mask.fill_path(
- &path,
- tiny_skia::FillRule::EvenOdd,
- true,
- transform,
- );
- let path_bounds = Rectangle {
- x: border_width / 2.0,
- y: border_width / 2.0,
- width: bounds.width - border_width,
- height: bounds.height - border_width,
- };
-
- let border_radius_path =
- rounded_rectangle(path_bounds, border_radius);
-
- temp_pixmap.stroke_path(
- &border_radius_path,
- &tiny_skia::Paint {
- shader: tiny_skia::Shader::SolidColor(
- into_color(border.color),
- ),
- anti_alias: true,
- ..tiny_skia::Paint::default()
- },
- &tiny_skia::Stroke {
- width: border_width,
- ..tiny_skia::Stroke::default()
- },
- transform,
- Some(&quad_mask),
- );
-
- pixels.draw_pixmap(
- bounds.x as i32,
- bounds.y as i32,
- temp_pixmap.as_ref(),
- &tiny_skia::PixmapPaint::default(),
- transform,
- clip_mask,
- );
- }
- }
- }
- Primitive::Paragraph {
- paragraph,
- position,
- color,
- clip_bounds: _, // TODO: Support text clip bounds
- } => {
- let physical_bounds =
- Rectangle::new(*position, paragraph.min_bounds)
- * transformation
- * scale_factor;
-
- if !clip_bounds.intersects(&physical_bounds) {
- return;
- }
-
- let clip_mask = (!physical_bounds.is_within(&clip_bounds))
- .then_some(clip_mask as &_);
-
- self.text_pipeline.draw_paragraph(
- paragraph,
- *position,
- *color,
- scale_factor,
- pixels,
- clip_mask,
- transformation,
- );
- }
- Primitive::Editor {
- editor,
- position,
- color,
- clip_bounds: _, // TODO: Support text clip bounds
- } => {
- let physical_bounds = Rectangle::new(*position, editor.bounds)
- * transformation
- * scale_factor;
-
- if !clip_bounds.intersects(&physical_bounds) {
- return;
- }
-
- let clip_mask = (!physical_bounds.is_within(&clip_bounds))
- .then_some(clip_mask as &_);
-
- self.text_pipeline.draw_editor(
- editor,
- *position,
- *color,
- scale_factor,
- pixels,
- clip_mask,
- transformation,
- );
- }
- Primitive::Text {
- content,
- bounds,
- color,
- size,
- line_height,
- font,
- horizontal_alignment,
- vertical_alignment,
- shaping,
- clip_bounds: _, // TODO: Support text clip bounds
- } => {
- let physical_bounds =
- primitive.bounds() * transformation * scale_factor;
-
- if !clip_bounds.intersects(&physical_bounds) {
- return;
- }
-
- let clip_mask = (!physical_bounds.is_within(&clip_bounds))
- .then_some(clip_mask as &_);
-
- self.text_pipeline.draw_cached(
- content,
- *bounds,
- *color,
- *size,
- *line_height,
- *font,
- *horizontal_alignment,
- *vertical_alignment,
- *shaping,
- scale_factor,
- pixels,
- clip_mask,
- transformation,
- );
- }
- Primitive::RawText(text::Raw {
- buffer,
- position,
- color,
- clip_bounds: _, // TODO: Support text clip bounds
- }) => {
- let Some(buffer) = buffer.upgrade() else {
- return;
- };
-
- let (width, height) = buffer.size();
-
- let physical_bounds =
- Rectangle::new(*position, Size::new(width, height))
- * transformation
- * scale_factor;
-
- if !clip_bounds.intersects(&physical_bounds) {
- return;
- }
-
- let clip_mask = (!physical_bounds.is_within(&clip_bounds))
- .then_some(clip_mask as &_);
-
- self.text_pipeline.draw_raw(
- &buffer,
- *position,
- *color,
- scale_factor,
- pixels,
- clip_mask,
- transformation,
- );
- }
- #[cfg(feature = "image")]
- Primitive::Image {
- handle,
- filter_method,
- bounds,
- } => {
- let physical_bounds = (*bounds * transformation) * scale_factor;
-
- if !clip_bounds.intersects(&physical_bounds) {
- return;
- }
-
- let clip_mask = (!physical_bounds.is_within(&clip_bounds))
- .then_some(clip_mask as &_);
-
- let transform = into_transform(transformation)
- .post_scale(scale_factor, scale_factor);
-
- self.raster_pipeline.draw(
- handle,
- *filter_method,
- *bounds,
- pixels,
- transform,
- clip_mask,
- );
- }
- #[cfg(not(feature = "image"))]
- Primitive::Image { .. } => {
- log::warn!(
- "Unsupported primitive in `iced_tiny_skia`: {primitive:?}",
- );
- }
- #[cfg(feature = "svg")]
- Primitive::Svg {
- handle,
- bounds,
- color,
- } => {
- let physical_bounds = (*bounds * transformation) * scale_factor;
-
- if !clip_bounds.intersects(&physical_bounds) {
- return;
- }
-
- let clip_mask = (!physical_bounds.is_within(&clip_bounds))
- .then_some(clip_mask as &_);
-
- self.vector_pipeline.draw(
- handle,
- *color,
- (*bounds * transformation) * scale_factor,
- pixels,
- clip_mask,
- );
- }
- #[cfg(not(feature = "svg"))]
- Primitive::Svg { .. } => {
- log::warn!(
- "Unsupported primitive in `iced_tiny_skia`: {primitive:?}",
- );
- }
- Primitive::Custom(primitive::Custom::Fill {
- path,
- paint,
- rule,
- }) => {
- let bounds = path.bounds();
-
- let physical_bounds = (Rectangle {
- x: bounds.x(),
- y: bounds.y(),
- width: bounds.width(),
- height: bounds.height(),
- } * transformation)
- * scale_factor;
-
- if !clip_bounds.intersects(&physical_bounds) {
- return;
- }
-
- let clip_mask = (!physical_bounds.is_within(&clip_bounds))
- .then_some(clip_mask as &_);
-
- pixels.fill_path(
- path,
- paint,
- *rule,
- into_transform(transformation)
- .post_scale(scale_factor, scale_factor),
- clip_mask,
- );
- }
- Primitive::Custom(primitive::Custom::Stroke {
- path,
- paint,
- stroke,
- }) => {
- let bounds = path.bounds();
-
- let physical_bounds = (Rectangle {
- x: bounds.x(),
- y: bounds.y(),
- width: bounds.width().max(1.0),
- height: bounds.height().max(1.0),
- } * transformation)
- * scale_factor;
-
- if !clip_bounds.intersects(&physical_bounds) {
- return;
- }
-
- let clip_mask = (!physical_bounds.is_within(&clip_bounds))
- .then_some(clip_mask as &_);
-
- pixels.stroke_path(
- path,
- paint,
- stroke,
- into_transform(transformation)
- .post_scale(scale_factor, scale_factor),
- clip_mask,
- );
- }
- Primitive::Group { primitives } => {
- for primitive in primitives {
- self.draw_primitive(
- primitive,
- pixels,
- clip_mask,
- clip_bounds,
- scale_factor,
- transformation,
- );
- }
- }
- Primitive::Transform {
- transformation: new_transformation,
- content,
- } => {
- self.draw_primitive(
- content,
- pixels,
- clip_mask,
- clip_bounds,
- scale_factor,
- transformation * *new_transformation,
- );
- }
- Primitive::Clip { bounds, content } => {
- let bounds = (*bounds * transformation) * scale_factor;
-
- if bounds == clip_bounds {
- self.draw_primitive(
- content,
- pixels,
- clip_mask,
- bounds,
- scale_factor,
- transformation,
- );
- } else if let Some(bounds) = clip_bounds.intersection(&bounds) {
- if bounds.x + bounds.width <= 0.0
- || bounds.y + bounds.height <= 0.0
- || bounds.x as u32 >= pixels.width()
- || bounds.y as u32 >= pixels.height()
- || bounds.width <= 1.0
- || bounds.height <= 1.0
- {
- return;
- }
-
- adjust_clip_mask(clip_mask, bounds);
-
- self.draw_primitive(
- content,
- pixels,
- clip_mask,
- bounds,
- scale_factor,
- transformation,
- );
-
- adjust_clip_mask(clip_mask, clip_bounds);
- }
- }
- Primitive::Cache { content } => {
- self.draw_primitive(
- content,
- pixels,
- clip_mask,
- clip_bounds,
- scale_factor,
- transformation,
- );
- }
- }
- }
-}
-
-impl Default for Backend {
- fn default() -> Self {
- Self::new()
- }
-}
-
-fn into_color(color: Color) -> tiny_skia::Color {
- tiny_skia::Color::from_rgba(color.b, color.g, color.r, color.a)
- .expect("Convert color from iced to tiny_skia")
-}
-
-fn into_transform(transformation: Transformation) -> tiny_skia::Transform {
- let translation = transformation.translation();
-
- tiny_skia::Transform {
- sx: transformation.scale_factor(),
- kx: 0.0,
- ky: 0.0,
- sy: transformation.scale_factor(),
- tx: translation.x,
- ty: translation.y,
- }
-}
-
-fn rounded_rectangle(
- bounds: Rectangle,
- border_radius: [f32; 4],
-) -> tiny_skia::Path {
- let [top_left, top_right, bottom_right, bottom_left] = border_radius;
-
- if top_left == 0.0
- && top_right == 0.0
- && bottom_right == 0.0
- && bottom_left == 0.0
- {
- return tiny_skia::PathBuilder::from_rect(
- tiny_skia::Rect::from_xywh(
- bounds.x,
- bounds.y,
- bounds.width,
- bounds.height,
- )
- .expect("Build quad rectangle"),
- );
- }
-
- if top_left == top_right
- && top_left == bottom_right
- && top_left == bottom_left
- && top_left == bounds.width / 2.0
- && top_left == bounds.height / 2.0
- {
- return tiny_skia::PathBuilder::from_circle(
- bounds.x + bounds.width / 2.0,
- bounds.y + bounds.height / 2.0,
- top_left,
- )
- .expect("Build circle path");
- }
-
- let mut builder = tiny_skia::PathBuilder::new();
-
- builder.move_to(bounds.x + top_left, bounds.y);
- builder.line_to(bounds.x + bounds.width - top_right, bounds.y);
-
- if top_right > 0.0 {
- arc_to(
- &mut builder,
- bounds.x + bounds.width - top_right,
- bounds.y,
- bounds.x + bounds.width,
- bounds.y + top_right,
- top_right,
- );
- }
-
- maybe_line_to(
- &mut builder,
- bounds.x + bounds.width,
- bounds.y + bounds.height - bottom_right,
- );
-
- if bottom_right > 0.0 {
- arc_to(
- &mut builder,
- bounds.x + bounds.width,
- bounds.y + bounds.height - bottom_right,
- bounds.x + bounds.width - bottom_right,
- bounds.y + bounds.height,
- bottom_right,
- );
- }
-
- maybe_line_to(
- &mut builder,
- bounds.x + bottom_left,
- bounds.y + bounds.height,
- );
-
- if bottom_left > 0.0 {
- arc_to(
- &mut builder,
- bounds.x + bottom_left,
- bounds.y + bounds.height,
- bounds.x,
- bounds.y + bounds.height - bottom_left,
- bottom_left,
- );
- }
-
- maybe_line_to(&mut builder, bounds.x, bounds.y + top_left);
-
- if top_left > 0.0 {
- arc_to(
- &mut builder,
- bounds.x,
- bounds.y + top_left,
- bounds.x + top_left,
- bounds.y,
- top_left,
- );
- }
-
- builder.finish().expect("Build rounded rectangle path")
-}
-
-fn maybe_line_to(path: &mut tiny_skia::PathBuilder, x: f32, y: f32) {
- if path.last_point() != Some(tiny_skia::Point { x, y }) {
- path.line_to(x, y);
- }
-}
-
-fn arc_to(
- path: &mut tiny_skia::PathBuilder,
- x_from: f32,
- y_from: f32,
- x_to: f32,
- y_to: f32,
- radius: f32,
-) {
- let svg_arc = kurbo::SvgArc {
- from: kurbo::Point::new(f64::from(x_from), f64::from(y_from)),
- to: kurbo::Point::new(f64::from(x_to), f64::from(y_to)),
- radii: kurbo::Vec2::new(f64::from(radius), f64::from(radius)),
- x_rotation: 0.0,
- large_arc: false,
- sweep: true,
- };
-
- match kurbo::Arc::from_svg_arc(&svg_arc) {
- Some(arc) => {
- arc.to_cubic_beziers(0.1, |p1, p2, p| {
- path.cubic_to(
- p1.x as f32,
- p1.y as f32,
- p2.x as f32,
- p2.y as f32,
- p.x as f32,
- p.y as f32,
- );
- });
- }
- None => {
- path.line_to(x_to, y_to);
- }
- }
-}
-
-fn adjust_clip_mask(clip_mask: &mut tiny_skia::Mask, bounds: Rectangle) {
- clip_mask.clear();
-
- let path = {
- let mut builder = tiny_skia::PathBuilder::new();
- builder.push_rect(
- tiny_skia::Rect::from_xywh(
- bounds.x,
- bounds.y,
- bounds.width,
- bounds.height,
- )
- .unwrap(),
- );
-
- builder.finish().unwrap()
- };
-
- clip_mask.fill_path(
- &path,
- tiny_skia::FillRule::EvenOdd,
- false,
- tiny_skia::Transform::default(),
- );
-}
-
-fn smoothstep(a: f32, b: f32, x: f32) -> f32 {
- let x = ((x - a) / (b - a)).clamp(0.0, 1.0);
-
- x * x * (3.0 - 2.0 * x)
-}
-
-fn rounded_box_sdf(
- to_center: Vector,
- size: tiny_skia::Size,
- radii: &[f32],
-) -> f32 {
- let radius = match (to_center.x > 0.0, to_center.y > 0.0) {
- (true, true) => radii[2],
- (true, false) => radii[1],
- (false, true) => radii[3],
- (false, false) => radii[0],
- };
-
- let x = (to_center.x.abs() - size.width() + radius).max(0.0);
- let y = (to_center.y.abs() - size.height() + radius).max(0.0);
-
- (x.powf(2.0) + y.powf(2.0)).sqrt() - radius
-}
-
-impl backend::Backend for Backend {
- type Primitive = primitive::Custom;
- type Compositor = window::Compositor;
-}
-
-impl backend::Text for Backend {
- fn load_font(&mut self, font: Cow<'static, [u8]>) {
- self.text_pipeline.load_font(font);
- }
-}
-
-#[cfg(feature = "image")]
-impl backend::Image for Backend {
- fn dimensions(
- &self,
- handle: &crate::core::image::Handle,
- ) -> crate::core::Size<u32> {
- self.raster_pipeline.dimensions(handle)
- }
-}
-
-#[cfg(feature = "svg")]
-impl backend::Svg for Backend {
- fn viewport_dimensions(
- &self,
- handle: &crate::core::svg::Handle,
- ) -> crate::core::Size<u32> {
- self.vector_pipeline.viewport_dimensions(handle)
- }
-}
-
-#[cfg(feature = "geometry")]
-impl crate::graphics::geometry::Backend for Backend {
- type Frame = crate::geometry::Frame;
-
- fn new_frame(&self, size: Size) -> Self::Frame {
- crate::geometry::Frame::new(size)
- }
-}