use std::sync::{Arc, Mutex};
use drawing_api::{smart_pointers::OptRef, PixelRect, RoundingRadii};
use super::{
convert_clip_operation, convert_color, convert_image_filter, convert_matrix, convert_point,
convert_radii, convert_rect, convert_texture_sampling, ImageFilterFragment,
};
pub struct DisplayListBuilder {
pub(crate) display_list_builder: impellers::DisplayListBuilder,
}
impl drawing_api::DisplayListBuilder for DisplayListBuilder {
type DisplayList = crate::DisplayList;
type ImageFilterFragment = crate::ImageFilterFragment;
type Paint = crate::Paint;
type ParagraphBuilder = crate::ParagraphBuilder;
type PathBuilder = crate::PathBuilder;
type Texture = crate::ImpellerTexture;
fn new(bounds: impl Into<Option<PixelRect>>) -> Self {
let bounds = bounds.into().map(|r| convert_rect(&r));
Self {
display_list_builder: impellers::DisplayListBuilder::new(bounds.as_ref()),
}
}
fn scale(&mut self, x_scale: f32, y_scale: f32) {
self.display_list_builder.scale(x_scale, y_scale);
}
fn rotate(&mut self, angle_degrees: f32) {
self.display_list_builder.rotate(angle_degrees);
}
fn translate(&mut self, x_translation: f32, y_translation: f32) {
self.display_list_builder
.translate(x_translation, y_translation);
}
fn transform(&mut self, transform: &drawing_api::Matrix) {
self.display_list_builder
.transform(&convert_matrix(transform));
}
fn set_transform(&mut self, transform: &drawing_api::Matrix) {
self.display_list_builder
.set_transform(&convert_matrix(transform));
}
fn get_transform(&self) -> drawing_api::Matrix {
convert_matrix(&self.display_list_builder.get_transform())
}
fn reset_transform(&mut self) {
self.display_list_builder.reset_transform();
}
fn clip_rect(&mut self, rect: impl Into<PixelRect>, operation: drawing_api::ClipOperation) {
let rect = convert_rect(&rect.into());
let operation = convert_clip_operation(&operation);
self.display_list_builder.clip_rect(&rect, operation);
}
fn clip_oval(
&mut self,
oval_bounds: impl Into<PixelRect>,
operation: drawing_api::ClipOperation,
) {
let oval_bounds = convert_rect(&oval_bounds.into());
let operation = convert_clip_operation(&operation);
self.display_list_builder.clip_oval(&oval_bounds, operation);
}
fn clip_rounded_rect<'a>(
&mut self,
rect: impl Into<PixelRect>,
radii: impl Into<OptRef<'a, RoundingRadii>>,
operation: drawing_api::ClipOperation,
) {
let rect = convert_rect(&rect.into());
let radii = convert_radii(&radii.into());
let operation = convert_clip_operation(&operation);
self.display_list_builder
.clip_rounded_rect(&rect, &radii, operation);
}
fn clip_path(
&mut self,
path: &<Self::PathBuilder as drawing_api::PathBuilder>::Path,
operation: drawing_api::ClipOperation,
) {
let operation = convert_clip_operation(&operation);
self.display_list_builder.clip_path(&path.path, operation);
}
fn save(&mut self) {
self.display_list_builder.save();
}
fn save_layer<'a>(
&mut self,
bounds: impl Into<drawing_api::PixelRect>,
paint: impl Into<Option<OptRef<'a, Self::Paint>>>,
filter: Option<drawing_api::ImageFilter<ImageFilterFragment>>,
) {
let bounds = convert_rect(&bounds.into());
let paint = paint.into();
match paint {
Some(paint) => self.display_list_builder.save_layer(
&bounds,
Some(&paint.paint.lock().unwrap()),
filter.map(|f| convert_image_filter(f)).as_ref(),
),
None => self.display_list_builder.save_layer(
&bounds,
None,
filter.map(|f| convert_image_filter(f)).as_ref(),
),
};
}
fn get_save_count(&mut self) -> usize {
self.display_list_builder.get_save_count() as usize
}
fn restore(&mut self) {
self.display_list_builder.restore();
}
fn restore_to_count(&mut self, count: usize) {
self.display_list_builder.restore_to_count(count as u32);
}
fn draw_paint<'a>(&mut self, paint: impl Into<OptRef<'a, Self::Paint>>) {
let paint = paint.into();
self.display_list_builder
.draw_paint(&paint.paint.lock().unwrap());
}
fn draw_line<'a>(
&mut self,
from: impl Into<drawing_api::PixelPoint>,
to: impl Into<drawing_api::PixelPoint>,
paint: impl Into<OptRef<'a, Self::Paint>>,
) {
let paint = paint.into();
self.display_list_builder.draw_line(
convert_point(&from.into()),
convert_point(&to.into()),
&paint.paint.lock().unwrap(),
);
}
fn draw_dashed_line<'a>(
&mut self,
from: impl Into<drawing_api::PixelPoint>,
to: impl Into<drawing_api::PixelPoint>,
on_length: f32,
off_length: f32,
paint: impl Into<OptRef<'a, Self::Paint>>,
) {
let paint = paint.into();
self.display_list_builder.draw_dashed_line(
convert_point(&from.into()),
convert_point(&to.into()),
on_length,
off_length,
&paint.paint.lock().unwrap(),
);
}
fn draw_rect<'a>(
&mut self,
rect: impl Into<drawing_api::PixelRect>,
paint: impl Into<OptRef<'a, Self::Paint>>,
) {
let paint = paint.into();
self.display_list_builder
.draw_rect(&convert_rect(&rect.into()), &paint.paint.lock().unwrap());
}
fn draw_rounded_rect<'a>(
&mut self,
rect: impl Into<PixelRect>,
radii: impl Into<OptRef<'a, RoundingRadii>>,
paint: impl Into<OptRef<'a, Self::Paint>>,
) {
let paint = paint.into();
self.display_list_builder.draw_rounded_rect(
&convert_rect(&rect.into()),
&convert_radii(&radii.into()),
&paint.paint.lock().unwrap(),
);
}
fn draw_rounded_rect_difference<'a>(
&mut self,
outer_rect: impl Into<PixelRect>,
outer_radii: impl Into<OptRef<'a, RoundingRadii>>,
inner_rect: impl Into<PixelRect>,
inner_radii: impl Into<OptRef<'a, RoundingRadii>>,
paint: impl Into<OptRef<'a, Self::Paint>>,
) {
let paint = paint.into();
self.display_list_builder.draw_rounded_rect_difference(
&convert_rect(&outer_rect.into()),
&convert_radii(&outer_radii.into()),
&convert_rect(&inner_rect.into()),
&convert_radii(&inner_radii.into()),
&paint.paint.lock().unwrap(),
);
}
fn draw_oval<'a>(
&mut self,
oval_bounds: impl Into<PixelRect>,
paint: impl Into<OptRef<'a, Self::Paint>>,
) {
let paint = paint.into();
self.display_list_builder.draw_oval(
&convert_rect(&oval_bounds.into()),
&paint.paint.lock().unwrap(),
);
}
fn draw_path<'a>(
&mut self,
path: &<Self::PathBuilder as drawing_api::PathBuilder>::Path,
paint: impl Into<OptRef<'a, Self::Paint>>,
) {
let paint = paint.into();
self.display_list_builder
.draw_path(&path.path, &paint.paint.lock().unwrap());
}
fn draw_shadow(
&mut self,
path: &<Self::PathBuilder as drawing_api::PathBuilder>::Path,
color: impl Into<drawing_api::Color>,
elevation: f32,
occluder_is_transparent: bool,
device_pixel_ratio: f32,
) {
self.display_list_builder.draw_shadow(
&path.path,
&convert_color(&color.into()),
elevation,
occluder_is_transparent,
device_pixel_ratio,
);
}
fn draw_texture<'a>(
&mut self,
texture: &Self::Texture,
point: impl Into<drawing_api::PixelPoint>,
sampling: drawing_api::TextureSampling,
paint: impl Into<Option<OptRef<'a, Self::Paint>>>,
) {
let paint = paint.into();
let paint = paint.unwrap_or_else(|| {
OptRef::Owned(Self::Paint {
paint: Arc::new(Mutex::new(impellers::Paint::default())),
})
});
self.display_list_builder.draw_texture(
&texture.texture,
convert_point(&point.into()),
convert_texture_sampling(sampling),
&paint.paint.lock().unwrap(),
);
}
fn draw_texture_rect<'a>(
&mut self,
texture: &Self::Texture,
src_rect: impl Into<drawing_api::PixelRect>,
dst_rect: impl Into<drawing_api::PixelRect>,
sampling: drawing_api::TextureSampling,
paint: impl Into<Option<OptRef<'a, Self::Paint>>>,
) {
let paint = paint.into();
match paint {
Some(paint) => self.display_list_builder.draw_texture_rect(
&texture.texture,
&convert_rect(&src_rect.into()),
&convert_rect(&dst_rect.into()),
convert_texture_sampling(sampling),
Some(&paint.paint.lock().unwrap()),
),
None => self.display_list_builder.draw_texture_rect(
&texture.texture,
&convert_rect(&src_rect.into()),
&convert_rect(&dst_rect.into()),
convert_texture_sampling(sampling),
None,
),
};
}
fn draw_paragraph(
&mut self,
location: impl Into<drawing_api::PixelPoint>,
paragraph: &<Self::ParagraphBuilder as drawing_api::ParagraphBuilder>::Paragraph,
) {
self.display_list_builder
.draw_paragraph(¶graph.paragraph, convert_point(&location.into()));
}
fn draw_display_list(&mut self, display_list: &Self::DisplayList, opacity: f32) {
self.display_list_builder
.draw_display_list(&display_list.display_list, opacity);
}
fn build(mut self) -> Result<Self::DisplayList, &'static str> {
Ok(crate::DisplayList {
display_list: self
.display_list_builder
.build()
.ok_or("Cannot build impeller display list")?,
})
}
}