summaryrefslogtreecommitdiffstats
path: root/tiny_skia/src
diff options
context:
space:
mode:
Diffstat (limited to 'tiny_skia/src')
-rw-r--r--tiny_skia/src/backend.rs102
-rw-r--r--tiny_skia/src/geometry.rs122
-rw-r--r--tiny_skia/src/primitive.rs4
-rw-r--r--tiny_skia/src/raster.rs12
-rw-r--r--tiny_skia/src/text.rs90
-rw-r--r--tiny_skia/src/vector.rs14
-rw-r--r--tiny_skia/src/window/compositor.rs141
7 files changed, 353 insertions, 132 deletions
diff --git a/tiny_skia/src/backend.rs b/tiny_skia/src/backend.rs
index 65aca4b0..d1393b4d 100644
--- a/tiny_skia/src/backend.rs
+++ b/tiny_skia/src/backend.rs
@@ -1,7 +1,7 @@
use crate::core::{Background, Color, Gradient, Rectangle, Vector};
use crate::graphics::backend;
use crate::graphics::text;
-use crate::graphics::{Damage, Viewport};
+use crate::graphics::Viewport;
use crate::primitive::{self, Primitive};
use std::borrow::Cow;
@@ -362,11 +362,10 @@ impl Backend {
paragraph,
position,
color,
+ clip_bounds: text_clip_bounds,
} => {
let physical_bounds =
- (Rectangle::new(*position, paragraph.min_bounds)
- + translation)
- * scale_factor;
+ (*text_clip_bounds + translation) * scale_factor;
if !clip_bounds.intersects(&physical_bounds) {
return;
@@ -384,6 +383,31 @@ impl Backend {
clip_mask,
);
}
+ Primitive::Editor {
+ editor,
+ position,
+ color,
+ clip_bounds: text_clip_bounds,
+ } => {
+ let physical_bounds =
+ (*text_clip_bounds + translation) * 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 + translation,
+ *color,
+ scale_factor,
+ pixels,
+ clip_mask,
+ );
+ }
Primitive::Text {
content,
bounds,
@@ -394,9 +418,10 @@ impl Backend {
horizontal_alignment,
vertical_alignment,
shaping,
+ clip_bounds: text_clip_bounds,
} => {
let physical_bounds =
- (primitive.bounds() + translation) * scale_factor;
+ (*text_clip_bounds + translation) * scale_factor;
if !clip_bounds.intersects(&physical_bounds) {
return;
@@ -420,8 +445,41 @@ impl Backend {
clip_mask,
);
}
+ Primitive::RawText(text::Raw {
+ buffer,
+ position,
+ color,
+ clip_bounds: text_clip_bounds,
+ }) => {
+ let Some(buffer) = buffer.upgrade() else {
+ return;
+ };
+
+ let physical_bounds =
+ (*text_clip_bounds + translation) * 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 + translation,
+ *color,
+ scale_factor,
+ pixels,
+ clip_mask,
+ );
+ }
#[cfg(feature = "image")]
- Primitive::Image { handle, bounds } => {
+ Primitive::Image {
+ handle,
+ filter_method,
+ bounds,
+ } => {
let physical_bounds = (*bounds + translation) * scale_factor;
if !clip_bounds.intersects(&physical_bounds) {
@@ -437,8 +495,14 @@ impl Backend {
)
.post_scale(scale_factor, scale_factor);
- self.raster_pipeline
- .draw(handle, *bounds, pixels, transform, clip_mask);
+ self.raster_pipeline.draw(
+ handle,
+ *filter_method,
+ *bounds,
+ pixels,
+ transform,
+ clip_mask,
+ );
}
#[cfg(not(feature = "image"))]
Primitive::Image { .. } => {
@@ -479,7 +543,6 @@ impl Backend {
path,
paint,
rule,
- transform,
}) => {
let bounds = path.bounds();
@@ -502,9 +565,11 @@ impl Backend {
path,
paint,
*rule,
- transform
- .post_translate(translation.x, translation.y)
- .post_scale(scale_factor, scale_factor),
+ tiny_skia::Transform::from_translate(
+ translation.x,
+ translation.y,
+ )
+ .post_scale(scale_factor, scale_factor),
clip_mask,
);
}
@@ -512,7 +577,6 @@ impl Backend {
path,
paint,
stroke,
- transform,
}) => {
let bounds = path.bounds();
@@ -535,9 +599,11 @@ impl Backend {
path,
paint,
stroke,
- transform
- .post_translate(translation.x, translation.y)
- .post_scale(scale_factor, scale_factor),
+ tiny_skia::Transform::from_translate(
+ translation.x,
+ translation.y,
+ )
+ .post_scale(scale_factor, scale_factor),
clip_mask,
);
}
@@ -803,10 +869,6 @@ impl iced_graphics::Backend for Backend {
}
impl backend::Text for Backend {
- fn font_system(&self) -> &text::FontSystem {
- self.text_pipeline.font_system()
- }
-
fn load_font(&mut self, font: Cow<'static, [u8]>) {
self.text_pipeline.load_font(font);
}
diff --git a/tiny_skia/src/geometry.rs b/tiny_skia/src/geometry.rs
index 1d14aa03..74a08d38 100644
--- a/tiny_skia/src/geometry.rs
+++ b/tiny_skia/src/geometry.rs
@@ -1,4 +1,5 @@
-use crate::core::{Point, Rectangle, Size, Vector};
+use crate::core::text::LineHeight;
+use crate::core::{Pixels, Point, Rectangle, Size, Vector};
use crate::graphics::geometry::fill::{self, Fill};
use crate::graphics::geometry::stroke::{self, Stroke};
use crate::graphics::geometry::{Path, Style, Text};
@@ -39,17 +40,22 @@ impl Frame {
}
pub fn fill(&mut self, path: &Path, fill: impl Into<Fill>) {
- let Some(path) = convert_path(path) else {
+ let Some(path) =
+ convert_path(path).and_then(|path| path.transform(self.transform))
+ else {
return;
};
+
let fill = fill.into();
+ let mut paint = into_paint(fill.style);
+ paint.shader.transform(self.transform);
+
self.primitives
.push(Primitive::Custom(primitive::Custom::Fill {
path,
- paint: into_paint(fill.style),
+ paint,
rule: into_fill_rule(fill.rule),
- transform: self.transform,
}));
}
@@ -59,73 +65,111 @@ impl Frame {
size: Size,
fill: impl Into<Fill>,
) {
- let Some(path) = convert_path(&Path::rectangle(top_left, size)) else {
+ let Some(path) = convert_path(&Path::rectangle(top_left, size))
+ .and_then(|path| path.transform(self.transform))
+ else {
return;
};
+
let fill = fill.into();
+ let mut paint = tiny_skia::Paint {
+ anti_alias: false,
+ ..into_paint(fill.style)
+ };
+ paint.shader.transform(self.transform);
+
self.primitives
.push(Primitive::Custom(primitive::Custom::Fill {
path,
- paint: tiny_skia::Paint {
- anti_alias: false,
- ..into_paint(fill.style)
- },
+ paint,
rule: into_fill_rule(fill.rule),
- transform: self.transform,
}));
}
pub fn stroke<'a>(&mut self, path: &Path, stroke: impl Into<Stroke<'a>>) {
- let Some(path) = convert_path(path) else {
+ let Some(path) =
+ convert_path(path).and_then(|path| path.transform(self.transform))
+ else {
return;
};
let stroke = stroke.into();
let skia_stroke = into_stroke(&stroke);
+ let mut paint = into_paint(stroke.style);
+ paint.shader.transform(self.transform);
+
self.primitives
.push(Primitive::Custom(primitive::Custom::Stroke {
path,
- paint: into_paint(stroke.style),
+ paint,
stroke: skia_stroke,
- transform: self.transform,
}));
}
pub fn fill_text(&mut self, text: impl Into<Text>) {
let text = text.into();
- let position = if self.transform.is_identity() {
- text.position
- } else {
- let mut transformed = [tiny_skia::Point {
- x: text.position.x,
- y: text.position.y,
- }];
-
- self.transform.map_points(&mut transformed);
-
- Point::new(transformed[0].x, transformed[0].y)
- };
-
- // TODO: Use vectorial text instead of primitive
- self.primitives.push(Primitive::Text {
- content: text.content,
- bounds: Rectangle {
+ let (scale_x, scale_y) = self.transform.get_scale();
+
+ if self.transform.is_scale_translate()
+ && scale_x == scale_y
+ && scale_x > 0.0
+ && scale_y > 0.0
+ {
+ let (position, size, line_height) = if self.transform.is_identity()
+ {
+ (text.position, text.size, text.line_height)
+ } else {
+ let mut position = [tiny_skia::Point {
+ x: text.position.x,
+ y: text.position.y,
+ }];
+
+ self.transform.map_points(&mut position);
+
+ let size = text.size.0 * scale_y;
+
+ let line_height = match text.line_height {
+ LineHeight::Absolute(size) => {
+ LineHeight::Absolute(Pixels(size.0 * scale_y))
+ }
+ LineHeight::Relative(factor) => {
+ LineHeight::Relative(factor)
+ }
+ };
+
+ (
+ Point::new(position[0].x, position[0].y),
+ size.into(),
+ line_height,
+ )
+ };
+
+ let bounds = Rectangle {
x: position.x,
y: position.y,
width: f32::INFINITY,
height: f32::INFINITY,
- },
- color: text.color,
- size: text.size,
- line_height: text.line_height,
- font: text.font,
- horizontal_alignment: text.horizontal_alignment,
- vertical_alignment: text.vertical_alignment,
- shaping: text.shaping,
- });
+ };
+
+ // TODO: Honor layering!
+ self.primitives.push(Primitive::Text {
+ content: text.content,
+ bounds,
+ color: text.color,
+ size,
+ line_height,
+ font: text.font,
+ horizontal_alignment: text.horizontal_alignment,
+ vertical_alignment: text.vertical_alignment,
+ shaping: text.shaping,
+ clip_bounds: Rectangle::with_size(Size::INFINITY),
+ });
+ } else {
+ text.draw_with(|path, color| self.fill(&path, color));
+ }
}
pub fn push_transform(&mut self) {
diff --git a/tiny_skia/src/primitive.rs b/tiny_skia/src/primitive.rs
index 0ed24969..7718d542 100644
--- a/tiny_skia/src/primitive.rs
+++ b/tiny_skia/src/primitive.rs
@@ -13,8 +13,6 @@ pub enum Custom {
paint: tiny_skia::Paint<'static>,
/// The fill rule to follow.
rule: tiny_skia::FillRule,
- /// The transform to apply to the path.
- transform: tiny_skia::Transform,
},
/// A path stroked with some paint.
Stroke {
@@ -24,8 +22,6 @@ pub enum Custom {
paint: tiny_skia::Paint<'static>,
/// The stroke settings.
stroke: tiny_skia::Stroke,
- /// The transform to apply to the path.
- transform: tiny_skia::Transform,
},
}
diff --git a/tiny_skia/src/raster.rs b/tiny_skia/src/raster.rs
index d13b1167..5f17ae60 100644
--- a/tiny_skia/src/raster.rs
+++ b/tiny_skia/src/raster.rs
@@ -28,6 +28,7 @@ impl Pipeline {
pub fn draw(
&mut self,
handle: &raster::Handle,
+ filter_method: raster::FilterMethod,
bounds: Rectangle,
pixels: &mut tiny_skia::PixmapMut<'_>,
transform: tiny_skia::Transform,
@@ -39,12 +40,21 @@ impl Pipeline {
let transform = transform.pre_scale(width_scale, height_scale);
+ let quality = match filter_method {
+ raster::FilterMethod::Linear => {
+ tiny_skia::FilterQuality::Bilinear
+ }
+ raster::FilterMethod::Nearest => {
+ tiny_skia::FilterQuality::Nearest
+ }
+ };
+
pixels.draw_pixmap(
(bounds.x / width_scale) as i32,
(bounds.y / height_scale) as i32,
image,
&tiny_skia::PixmapPaint {
- quality: tiny_skia::FilterQuality::Bilinear,
+ quality,
..Default::default()
},
transform,
diff --git a/tiny_skia/src/text.rs b/tiny_skia/src/text.rs
index cb3ef54c..9413e311 100644
--- a/tiny_skia/src/text.rs
+++ b/tiny_skia/src/text.rs
@@ -1,9 +1,10 @@
use crate::core::alignment;
use crate::core::text::{LineHeight, Shaping};
-use crate::core::{Color, Font, Pixels, Point, Rectangle};
+use crate::core::{Color, Font, Pixels, Point, Rectangle, Size};
use crate::graphics::text::cache::{self, Cache};
+use crate::graphics::text::editor;
+use crate::graphics::text::font_system;
use crate::graphics::text::paragraph;
-use crate::graphics::text::FontSystem;
use rustc_hash::{FxHashMap, FxHashSet};
use std::borrow::Cow;
@@ -12,7 +13,6 @@ use std::collections::hash_map;
#[allow(missing_debug_implementations)]
pub struct Pipeline {
- font_system: FontSystem,
glyph_cache: GlyphCache,
cache: RefCell<Cache>,
}
@@ -20,18 +20,16 @@ pub struct Pipeline {
impl Pipeline {
pub fn new() -> Self {
Pipeline {
- font_system: FontSystem::new(),
glyph_cache: GlyphCache::new(),
cache: RefCell::new(Cache::new()),
}
}
- pub fn font_system(&self) -> &FontSystem {
- &self.font_system
- }
-
pub fn load_font(&mut self, bytes: Cow<'static, [u8]>) {
- self.font_system.load_font(bytes);
+ font_system()
+ .write()
+ .expect("Write font system")
+ .load_font(bytes);
self.cache = RefCell::new(Cache::new());
}
@@ -51,8 +49,10 @@ impl Pipeline {
return;
};
+ let mut font_system = font_system().write().expect("Write font system");
+
draw(
- self.font_system.get_mut(),
+ font_system.raw(),
&mut self.glyph_cache,
paragraph.buffer(),
Rectangle::new(position, paragraph.min_bounds()),
@@ -65,6 +65,37 @@ impl Pipeline {
);
}
+ pub fn draw_editor(
+ &mut self,
+ editor: &editor::Weak,
+ position: Point,
+ color: Color,
+ scale_factor: f32,
+ pixels: &mut tiny_skia::PixmapMut<'_>,
+ clip_mask: Option<&tiny_skia::Mask>,
+ ) {
+ use crate::core::text::Editor as _;
+
+ let Some(editor) = editor.upgrade() else {
+ return;
+ };
+
+ let mut font_system = font_system().write().expect("Write font system");
+
+ draw(
+ font_system.raw(),
+ &mut self.glyph_cache,
+ editor.buffer(),
+ Rectangle::new(position, editor.bounds()),
+ color,
+ alignment::Horizontal::Left,
+ alignment::Vertical::Top,
+ scale_factor,
+ pixels,
+ clip_mask,
+ );
+ }
+
pub fn draw_cached(
&mut self,
content: &str,
@@ -82,7 +113,9 @@ impl Pipeline {
) {
let line_height = f32::from(line_height.to_absolute(size));
- let font_system = self.font_system.get_mut();
+ let mut font_system = font_system().write().expect("Write font system");
+ let font_system = font_system.raw();
+
let key = cache::Key {
bounds: bounds.size(),
content,
@@ -115,6 +148,33 @@ impl Pipeline {
);
}
+ pub fn draw_raw(
+ &mut self,
+ buffer: &cosmic_text::Buffer,
+ position: Point,
+ color: Color,
+ scale_factor: f32,
+ pixels: &mut tiny_skia::PixmapMut<'_>,
+ clip_mask: Option<&tiny_skia::Mask>,
+ ) {
+ let mut font_system = font_system().write().expect("Write font system");
+
+ let (width, height) = buffer.size();
+
+ draw(
+ font_system.raw(),
+ &mut self.glyph_cache,
+ buffer,
+ Rectangle::new(position, Size::new(width, height)),
+ color,
+ alignment::Horizontal::Left,
+ alignment::Vertical::Top,
+ scale_factor,
+ pixels,
+ clip_mask,
+ );
+ }
+
pub fn trim_cache(&mut self) {
self.cache.get_mut().trim();
self.glyph_cache.trim();
@@ -155,7 +215,7 @@ fn draw(
if let Some((buffer, placement)) = glyph_cache.allocate(
physical_glyph.cache_key,
- color,
+ glyph.color_opt.map(from_color).unwrap_or(color),
font_system,
&mut swash,
) {
@@ -180,6 +240,12 @@ fn draw(
}
}
+fn from_color(color: cosmic_text::Color) -> Color {
+ let [r, g, b, a] = color.as_rgba();
+
+ Color::from_rgba8(r, g, b, a as f32 / 255.0)
+}
+
#[derive(Debug, Clone, Default)]
struct GlyphCache {
entries: FxHashMap<
diff --git a/tiny_skia/src/vector.rs b/tiny_skia/src/vector.rs
index a1cd269d..fd1ab3de 100644
--- a/tiny_skia/src/vector.rs
+++ b/tiny_skia/src/vector.rs
@@ -1,7 +1,8 @@
use crate::core::svg::{Data, Handle};
use crate::core::{Color, Rectangle, Size};
+use crate::graphics::text;
-use resvg::usvg;
+use resvg::usvg::{self, TreeTextToPath};
use rustc_hash::{FxHashMap, FxHashSet};
use std::cell::RefCell;
@@ -77,7 +78,7 @@ impl Cache {
let id = handle.id();
if let hash_map::Entry::Vacant(entry) = self.trees.entry(id) {
- let svg = match handle.data() {
+ let mut svg = match handle.data() {
Data::Path(path) => {
fs::read_to_string(path).ok().and_then(|contents| {
usvg::Tree::from_str(
@@ -92,6 +93,15 @@ impl Cache {
}
};
+ if let Some(svg) = &mut svg {
+ if svg.has_text_nodes() {
+ let mut font_system =
+ text::font_system().write().expect("Write font system");
+
+ svg.convert_text(font_system.raw().db_mut());
+ }
+ }
+
let _ = entry.insert(svg);
}
diff --git a/tiny_skia/src/window/compositor.rs b/tiny_skia/src/window/compositor.rs
index 828e522f..781ed8a5 100644
--- a/tiny_skia/src/window/compositor.rs
+++ b/tiny_skia/src/window/compositor.rs
@@ -4,19 +4,25 @@ use crate::graphics::damage;
use crate::graphics::{Error, Viewport};
use crate::{Backend, Primitive, Renderer, Settings};
-use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
+use std::collections::VecDeque;
use std::marker::PhantomData;
+use std::num::NonZeroU32;
pub struct Compositor<Theme> {
+ context: softbuffer::Context<Box<dyn compositor::Window>>,
+ settings: Settings,
_theme: PhantomData<Theme>,
}
pub struct Surface {
- window: softbuffer::GraphicsContext,
- buffer: Vec<u32>,
+ window: softbuffer::Surface<
+ Box<dyn compositor::Window>,
+ Box<dyn compositor::Window>,
+ >,
clip_mask: tiny_skia::Mask,
- primitives: Option<Vec<Primitive>>,
+ primitive_stack: VecDeque<Vec<Primitive>>,
background_color: Color,
+ max_age: u8,
}
impl<Theme> crate::graphics::Compositor for Compositor<Theme> {
@@ -24,53 +30,64 @@ impl<Theme> crate::graphics::Compositor for Compositor<Theme> {
type Renderer = Renderer<Theme>;
type Surface = Surface;
- fn new<W: HasRawWindowHandle + HasRawDisplayHandle>(
+ fn new<W: compositor::Window>(
settings: Self::Settings,
- _compatible_window: Option<&W>,
- ) -> Result<(Self, Self::Renderer), Error> {
- let (compositor, backend) = new();
+ compatible_window: W,
+ ) -> Result<Self, Error> {
+ Ok(new(settings, compatible_window))
+ }
- Ok((
- compositor,
- Renderer::new(
- backend,
- settings.default_font,
- settings.default_text_size,
- ),
- ))
+ fn create_renderer(&self) -> Self::Renderer {
+ Renderer::new(
+ Backend::new(),
+ self.settings.default_font,
+ self.settings.default_text_size,
+ )
}
- fn create_surface<W: HasRawWindowHandle + HasRawDisplayHandle>(
+ fn create_surface<W: compositor::Window + Clone>(
&mut self,
- window: &W,
+ window: W,
width: u32,
height: u32,
- ) -> Surface {
- #[allow(unsafe_code)]
- let window =
- unsafe { softbuffer::GraphicsContext::new(window, window) }
- .expect("Create softbuffer for window");
+ ) -> Self::Surface {
+ let window = softbuffer::Surface::new(
+ &self.context,
+ Box::new(window.clone()) as _,
+ )
+ .expect("Create softbuffer surface for window");
- Surface {
+ let mut surface = Surface {
window,
- buffer: vec![0; width as usize * height as usize],
clip_mask: tiny_skia::Mask::new(width, height)
.expect("Create clip mask"),
- primitives: None,
+ primitive_stack: VecDeque::new(),
background_color: Color::BLACK,
- }
+ max_age: 0,
+ };
+
+ self.configure_surface(&mut surface, width, height);
+
+ surface
}
fn configure_surface(
&mut self,
- surface: &mut Surface,
+ surface: &mut Self::Surface,
width: u32,
height: u32,
) {
- surface.buffer.resize((width * height) as usize, 0);
+ surface
+ .window
+ .resize(
+ NonZeroU32::new(width).expect("Non-zero width"),
+ NonZeroU32::new(height).expect("Non-zero height"),
+ )
+ .expect("Resize surface");
+
surface.clip_mask =
tiny_skia::Mask::new(width, height).expect("Create clip mask");
- surface.primitives = None;
+ surface.primitive_stack.clear();
}
fn fetch_information(&self) -> Information {
@@ -121,13 +138,19 @@ impl<Theme> crate::graphics::Compositor for Compositor<Theme> {
}
}
-pub fn new<Theme>() -> (Compositor<Theme>, Backend) {
- (
- Compositor {
- _theme: PhantomData,
- },
- Backend::new(),
- )
+pub fn new<W: compositor::Window, Theme>(
+ settings: Settings,
+ compatible_window: W,
+) -> Compositor<Theme> {
+ #[allow(unsafe_code)]
+ let context = softbuffer::Context::new(Box::new(compatible_window) as _)
+ .expect("Create softbuffer context");
+
+ Compositor {
+ context,
+ settings,
+ _theme: PhantomData,
+ }
}
pub fn present<T: AsRef<str>>(
@@ -141,16 +164,25 @@ pub fn present<T: AsRef<str>>(
let physical_size = viewport.physical_size();
let scale_factor = viewport.scale_factor() as f32;
- let mut pixels = tiny_skia::PixmapMut::from_bytes(
- bytemuck::cast_slice_mut(&mut surface.buffer),
- physical_size.width,
- physical_size.height,
- )
- .expect("Create pixel map");
+ let mut buffer = surface
+ .window
+ .buffer_mut()
+ .map_err(|_| compositor::SurfaceError::Lost)?;
+
+ let last_primitives = {
+ let age = buffer.age();
- let damage = surface
- .primitives
- .as_deref()
+ surface.max_age = surface.max_age.max(age);
+ surface.primitive_stack.truncate(surface.max_age as usize);
+
+ if age > 0 {
+ surface.primitive_stack.get(age as usize - 1)
+ } else {
+ None
+ }
+ };
+
+ let damage = last_primitives
.and_then(|last_primitives| {
(surface.background_color == background_color)
.then(|| damage::list(last_primitives, primitives))
@@ -161,11 +193,18 @@ pub fn present<T: AsRef<str>>(
return Ok(());
}
- surface.primitives = Some(primitives.to_vec());
+ surface.primitive_stack.push_front(primitives.to_vec());
surface.background_color = background_color;
let damage = damage::group(damage, scale_factor, physical_size);
+ let mut pixels = tiny_skia::PixmapMut::from_bytes(
+ bytemuck::cast_slice_mut(&mut buffer),
+ physical_size.width,
+ physical_size.height,
+ )
+ .expect("Create pixel map");
+
backend.draw(
&mut pixels,
&mut surface.clip_mask,
@@ -176,13 +215,7 @@ pub fn present<T: AsRef<str>>(
overlay,
);
- surface.window.set_buffer(
- &surface.buffer,
- physical_size.width as u16,
- physical_size.height as u16,
- );
-
- Ok(())
+ buffer.present().map_err(|_| compositor::SurfaceError::Lost)
}
pub fn screenshot<T: AsRef<str>>(