Merge branch 'master' into beacon
This commit is contained in:
commit
8bd5de72ea
371 changed files with 33138 additions and 12950 deletions
|
|
@ -15,7 +15,7 @@ workspace = true
|
|||
|
||||
[features]
|
||||
image = ["iced_graphics/image"]
|
||||
svg = ["resvg"]
|
||||
svg = ["iced_graphics/svg", "resvg"]
|
||||
geometry = ["iced_graphics/geometry"]
|
||||
|
||||
[dependencies]
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use crate::Primitive;
|
||||
use crate::core::renderer::Quad;
|
||||
use crate::core::{
|
||||
Background, Color, Gradient, Rectangle, Size, Transformation, Vector,
|
||||
};
|
||||
use crate::graphics::{Image, Text};
|
||||
use crate::text;
|
||||
use crate::Primitive;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Engine {
|
||||
|
|
@ -439,9 +439,13 @@ impl Engine {
|
|||
let transformation = transformation * *local_transformation;
|
||||
let (width, height) = buffer.size();
|
||||
|
||||
let physical_bounds =
|
||||
Rectangle::new(raw.position, Size::new(width, height))
|
||||
* transformation;
|
||||
let physical_bounds = Rectangle::new(
|
||||
raw.position,
|
||||
Size::new(
|
||||
width.unwrap_or(clip_bounds.width),
|
||||
height.unwrap_or(clip_bounds.height),
|
||||
),
|
||||
) * transformation;
|
||||
|
||||
if !clip_bounds.intersects(&physical_bounds) {
|
||||
return;
|
||||
|
|
@ -546,13 +550,7 @@ impl Engine {
|
|||
) {
|
||||
match image {
|
||||
#[cfg(feature = "image")]
|
||||
Image::Raster {
|
||||
handle,
|
||||
filter_method,
|
||||
bounds,
|
||||
rotation,
|
||||
opacity,
|
||||
} => {
|
||||
Image::Raster(raster, bounds) => {
|
||||
let physical_bounds = *bounds * _transformation;
|
||||
|
||||
if !_clip_bounds.intersects(&physical_bounds) {
|
||||
|
|
@ -563,7 +561,7 @@ impl Engine {
|
|||
.then_some(_clip_mask as &_);
|
||||
|
||||
let center = physical_bounds.center();
|
||||
let radians = f32::from(*rotation);
|
||||
let radians = f32::from(raster.rotation);
|
||||
|
||||
let transform = into_transform(_transformation).post_rotate_at(
|
||||
radians.to_degrees(),
|
||||
|
|
@ -572,23 +570,17 @@ impl Engine {
|
|||
);
|
||||
|
||||
self.raster_pipeline.draw(
|
||||
handle,
|
||||
*filter_method,
|
||||
&raster.handle,
|
||||
raster.filter_method,
|
||||
*bounds,
|
||||
*opacity,
|
||||
raster.opacity,
|
||||
_pixels,
|
||||
transform,
|
||||
clip_mask,
|
||||
);
|
||||
}
|
||||
#[cfg(feature = "svg")]
|
||||
Image::Vector {
|
||||
handle,
|
||||
color,
|
||||
bounds,
|
||||
rotation,
|
||||
opacity,
|
||||
} => {
|
||||
Image::Vector(svg, bounds) => {
|
||||
let physical_bounds = *bounds * _transformation;
|
||||
|
||||
if !_clip_bounds.intersects(&physical_bounds) {
|
||||
|
|
@ -599,7 +591,7 @@ impl Engine {
|
|||
.then_some(_clip_mask as &_);
|
||||
|
||||
let center = physical_bounds.center();
|
||||
let radians = f32::from(*rotation);
|
||||
let radians = f32::from(svg.rotation);
|
||||
|
||||
let transform = into_transform(_transformation).post_rotate_at(
|
||||
radians.to_degrees(),
|
||||
|
|
@ -608,10 +600,10 @@ impl Engine {
|
|||
);
|
||||
|
||||
self.vector_pipeline.draw(
|
||||
handle,
|
||||
*color,
|
||||
&svg.handle,
|
||||
svg.color,
|
||||
physical_bounds,
|
||||
*opacity,
|
||||
svg.opacity,
|
||||
_pixels,
|
||||
transform,
|
||||
clip_mask,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
use crate::Primitive;
|
||||
use crate::core::text::LineHeight;
|
||||
use crate::core::{Pixels, Point, Radians, Rectangle, Size, Vector};
|
||||
use crate::core::{self, Pixels, Point, Radians, Rectangle, Size, Svg, Vector};
|
||||
use crate::graphics::cache::{self, Cached};
|
||||
use crate::graphics::geometry::fill::{self, Fill};
|
||||
use crate::graphics::geometry::stroke::{self, Stroke};
|
||||
use crate::graphics::geometry::{self, Path, Style};
|
||||
use crate::graphics::{Gradient, Text};
|
||||
use crate::Primitive;
|
||||
use crate::graphics::{self, Gradient, Image, Text};
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -13,6 +13,7 @@ use std::rc::Rc;
|
|||
pub enum Geometry {
|
||||
Live {
|
||||
text: Vec<Text>,
|
||||
images: Vec<graphics::Image>,
|
||||
primitives: Vec<Primitive>,
|
||||
clip_bounds: Rectangle,
|
||||
},
|
||||
|
|
@ -22,6 +23,7 @@ pub enum Geometry {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct Cache {
|
||||
pub text: Rc<[Text]>,
|
||||
pub images: Rc<[graphics::Image]>,
|
||||
pub primitives: Rc<[Primitive]>,
|
||||
pub clip_bounds: Rectangle,
|
||||
}
|
||||
|
|
@ -37,10 +39,12 @@ impl Cached for Geometry {
|
|||
match self {
|
||||
Self::Live {
|
||||
primitives,
|
||||
images,
|
||||
text,
|
||||
clip_bounds,
|
||||
} => Cache {
|
||||
primitives: Rc::from(primitives),
|
||||
images: Rc::from(images),
|
||||
text: Rc::from(text),
|
||||
clip_bounds,
|
||||
},
|
||||
|
|
@ -55,6 +59,7 @@ pub struct Frame {
|
|||
transform: tiny_skia::Transform,
|
||||
stack: Vec<tiny_skia::Transform>,
|
||||
primitives: Vec<Primitive>,
|
||||
images: Vec<graphics::Image>,
|
||||
text: Vec<Text>,
|
||||
}
|
||||
|
||||
|
|
@ -68,6 +73,7 @@ impl Frame {
|
|||
clip_bounds,
|
||||
stack: Vec::new(),
|
||||
primitives: Vec::new(),
|
||||
images: Vec::new(),
|
||||
text: Vec::new(),
|
||||
transform: tiny_skia::Transform::from_translate(
|
||||
clip_bounds.x,
|
||||
|
|
@ -162,6 +168,15 @@ impl geometry::frame::Backend for Frame {
|
|||
});
|
||||
}
|
||||
|
||||
fn stroke_rectangle<'a>(
|
||||
&mut self,
|
||||
top_left: Point,
|
||||
size: Size,
|
||||
stroke: impl Into<Stroke<'a>>,
|
||||
) {
|
||||
self.stroke(&Path::rectangle(top_left, size), stroke);
|
||||
}
|
||||
|
||||
fn fill_text(&mut self, text: impl Into<geometry::Text>) {
|
||||
let text = text.into();
|
||||
|
||||
|
|
@ -238,9 +253,10 @@ impl geometry::frame::Backend for Frame {
|
|||
Self::with_clip(clip_bounds)
|
||||
}
|
||||
|
||||
fn paste(&mut self, frame: Self, _at: Point) {
|
||||
fn paste(&mut self, frame: Self) {
|
||||
self.primitives.extend(frame.primitives);
|
||||
self.text.extend(frame.text);
|
||||
self.images.extend(frame.images);
|
||||
}
|
||||
|
||||
fn translate(&mut self, translation: Vector) {
|
||||
|
|
@ -269,10 +285,63 @@ impl geometry::frame::Backend for Frame {
|
|||
fn into_geometry(self) -> Geometry {
|
||||
Geometry::Live {
|
||||
primitives: self.primitives,
|
||||
images: self.images,
|
||||
text: self.text,
|
||||
clip_bounds: self.clip_bounds,
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_image(&mut self, bounds: Rectangle, image: impl Into<core::Image>) {
|
||||
let mut image = image.into();
|
||||
|
||||
let (bounds, external_rotation) =
|
||||
transform_rectangle(bounds, self.transform);
|
||||
|
||||
image.rotation += external_rotation;
|
||||
|
||||
self.images.push(graphics::Image::Raster(image, bounds));
|
||||
}
|
||||
|
||||
fn draw_svg(&mut self, bounds: Rectangle, svg: impl Into<Svg>) {
|
||||
let mut svg = svg.into();
|
||||
|
||||
let (bounds, external_rotation) =
|
||||
transform_rectangle(bounds, self.transform);
|
||||
|
||||
svg.rotation += external_rotation;
|
||||
|
||||
self.images.push(Image::Vector(svg, bounds));
|
||||
}
|
||||
}
|
||||
|
||||
fn transform_rectangle(
|
||||
rectangle: Rectangle,
|
||||
transform: tiny_skia::Transform,
|
||||
) -> (Rectangle, Radians) {
|
||||
let mut top_left = tiny_skia::Point {
|
||||
x: rectangle.x,
|
||||
y: rectangle.y,
|
||||
};
|
||||
|
||||
let mut top_right = tiny_skia::Point {
|
||||
x: rectangle.x + rectangle.width,
|
||||
y: rectangle.y,
|
||||
};
|
||||
|
||||
let mut bottom_left = tiny_skia::Point {
|
||||
x: rectangle.x,
|
||||
y: rectangle.y + rectangle.height,
|
||||
};
|
||||
|
||||
transform.map_point(&mut top_left);
|
||||
transform.map_point(&mut top_right);
|
||||
transform.map_point(&mut bottom_left);
|
||||
|
||||
Rectangle::with_vertices(
|
||||
Point::new(top_left.x, top_left.y),
|
||||
Point::new(top_right.x, top_right.y),
|
||||
Point::new(bottom_left.x, bottom_left.y),
|
||||
)
|
||||
}
|
||||
|
||||
fn convert_path(path: &Path) -> Option<tiny_skia::Path> {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
use crate::Primitive;
|
||||
use crate::core::renderer::Quad;
|
||||
use crate::core::{
|
||||
image, renderer::Quad, svg, Background, Color, Point, Radians, Rectangle,
|
||||
Transformation,
|
||||
self, Background, Color, Point, Rectangle, Svg, Transformation,
|
||||
};
|
||||
use crate::graphics::damage;
|
||||
use crate::graphics::layer;
|
||||
use crate::graphics::text::{Editor, Paragraph, Text};
|
||||
use crate::graphics::{self, Image};
|
||||
use crate::Primitive;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ impl Layer {
|
|||
|
||||
pub fn draw_text(
|
||||
&mut self,
|
||||
text: crate::core::Text,
|
||||
text: core::Text,
|
||||
position: Point,
|
||||
color: Color,
|
||||
clip_bounds: Rectangle,
|
||||
|
|
@ -115,42 +115,35 @@ impl Layer {
|
|||
.push(Item::Cached(text, clip_bounds, transformation));
|
||||
}
|
||||
|
||||
pub fn draw_image(
|
||||
pub fn draw_image(&mut self, image: Image, transformation: Transformation) {
|
||||
match image {
|
||||
Image::Raster(raster, bounds) => {
|
||||
self.draw_raster(raster, bounds, transformation);
|
||||
}
|
||||
Image::Vector(svg, bounds) => {
|
||||
self.draw_svg(svg, bounds, transformation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_raster(
|
||||
&mut self,
|
||||
handle: image::Handle,
|
||||
filter_method: image::FilterMethod,
|
||||
image: core::Image,
|
||||
bounds: Rectangle,
|
||||
transformation: Transformation,
|
||||
rotation: Radians,
|
||||
opacity: f32,
|
||||
) {
|
||||
let image = Image::Raster {
|
||||
handle,
|
||||
filter_method,
|
||||
bounds: bounds * transformation,
|
||||
rotation,
|
||||
opacity,
|
||||
};
|
||||
let image = Image::Raster(image, bounds * transformation);
|
||||
|
||||
self.images.push(image);
|
||||
}
|
||||
|
||||
pub fn draw_svg(
|
||||
&mut self,
|
||||
handle: svg::Handle,
|
||||
color: Option<Color>,
|
||||
svg: Svg,
|
||||
bounds: Rectangle,
|
||||
transformation: Transformation,
|
||||
rotation: Radians,
|
||||
opacity: f32,
|
||||
) {
|
||||
let svg = Image::Vector {
|
||||
handle,
|
||||
color,
|
||||
bounds: bounds * transformation,
|
||||
rotation,
|
||||
opacity,
|
||||
};
|
||||
let svg = Image::Vector(svg, bounds * transformation);
|
||||
|
||||
self.images.push(svg);
|
||||
}
|
||||
|
|
@ -293,7 +286,7 @@ impl graphics::Layer for Layer {
|
|||
|
||||
fn flush(&mut self) {}
|
||||
|
||||
fn resize(&mut self, bounds: graphics::core::Rectangle) {
|
||||
fn resize(&mut self, bounds: Rectangle) {
|
||||
self.bounds = bounds;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,12 +29,12 @@ pub use geometry::Geometry;
|
|||
|
||||
use crate::core::renderer;
|
||||
use crate::core::{
|
||||
Background, Color, Font, Pixels, Point, Rectangle, Transformation,
|
||||
Background, Color, Font, Pixels, Point, Rectangle, Size, Transformation,
|
||||
};
|
||||
use crate::engine::Engine;
|
||||
use crate::graphics::Viewport;
|
||||
use crate::graphics::compositor;
|
||||
use crate::graphics::text::{Editor, Paragraph};
|
||||
use crate::graphics::Viewport;
|
||||
|
||||
/// A [`tiny-skia`] graphics renderer for [`iced`].
|
||||
///
|
||||
|
|
@ -147,6 +147,16 @@ impl Renderer {
|
|||
engine::adjust_clip_mask(clip_mask, clip_bounds);
|
||||
}
|
||||
|
||||
for image in &layer.images {
|
||||
self.engine.draw_image(
|
||||
image,
|
||||
Transformation::scale(scale_factor),
|
||||
pixels,
|
||||
clip_mask,
|
||||
clip_bounds,
|
||||
);
|
||||
}
|
||||
|
||||
for group in &layer.text {
|
||||
for text in group.as_slice() {
|
||||
self.engine.draw_text(
|
||||
|
|
@ -159,16 +169,6 @@ impl Renderer {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
for image in &layer.images {
|
||||
self.engine.draw_image(
|
||||
image,
|
||||
Transformation::scale(scale_factor),
|
||||
pixels,
|
||||
clip_mask,
|
||||
clip_bounds,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -280,6 +280,7 @@ impl graphics::geometry::Renderer for Renderer {
|
|||
match geometry {
|
||||
Geometry::Live {
|
||||
primitives,
|
||||
images,
|
||||
text,
|
||||
clip_bounds,
|
||||
} => {
|
||||
|
|
@ -289,6 +290,10 @@ impl graphics::geometry::Renderer for Renderer {
|
|||
transformation,
|
||||
);
|
||||
|
||||
for image in images {
|
||||
layer.draw_image(image, transformation);
|
||||
}
|
||||
|
||||
layer.draw_text_group(text, clip_bounds, transformation);
|
||||
}
|
||||
Geometry::Cache(cache) => {
|
||||
|
|
@ -298,6 +303,10 @@ impl graphics::geometry::Renderer for Renderer {
|
|||
transformation,
|
||||
);
|
||||
|
||||
for image in cache.images.iter() {
|
||||
layer.draw_image(image.clone(), transformation);
|
||||
}
|
||||
|
||||
layer.draw_text_cache(
|
||||
cache.text,
|
||||
cache.clip_bounds,
|
||||
|
|
@ -322,23 +331,9 @@ impl core::image::Renderer for Renderer {
|
|||
self.engine.raster_pipeline.dimensions(handle)
|
||||
}
|
||||
|
||||
fn draw_image(
|
||||
&mut self,
|
||||
handle: Self::Handle,
|
||||
filter_method: core::image::FilterMethod,
|
||||
bounds: Rectangle,
|
||||
rotation: core::Radians,
|
||||
opacity: f32,
|
||||
) {
|
||||
fn draw_image(&mut self, image: core::Image, bounds: Rectangle) {
|
||||
let (layer, transformation) = self.layers.current_mut();
|
||||
layer.draw_image(
|
||||
handle,
|
||||
filter_method,
|
||||
bounds,
|
||||
transformation,
|
||||
rotation,
|
||||
opacity,
|
||||
);
|
||||
layer.draw_raster(image, bounds, transformation);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -351,26 +346,30 @@ impl core::svg::Renderer for Renderer {
|
|||
self.engine.vector_pipeline.viewport_dimensions(handle)
|
||||
}
|
||||
|
||||
fn draw_svg(
|
||||
&mut self,
|
||||
handle: core::svg::Handle,
|
||||
color: Option<Color>,
|
||||
bounds: Rectangle,
|
||||
rotation: core::Radians,
|
||||
opacity: f32,
|
||||
) {
|
||||
fn draw_svg(&mut self, svg: core::Svg, bounds: Rectangle) {
|
||||
let (layer, transformation) = self.layers.current_mut();
|
||||
layer.draw_svg(
|
||||
handle,
|
||||
color,
|
||||
bounds,
|
||||
transformation,
|
||||
rotation,
|
||||
opacity,
|
||||
);
|
||||
layer.draw_svg(svg, bounds, transformation);
|
||||
}
|
||||
}
|
||||
|
||||
impl compositor::Default for Renderer {
|
||||
type Compositor = window::Compositor;
|
||||
}
|
||||
|
||||
impl renderer::Headless for Renderer {
|
||||
fn new(default_font: Font, default_text_size: Pixels) -> Self {
|
||||
Self::new(default_font, default_text_size)
|
||||
}
|
||||
|
||||
fn screenshot(
|
||||
&mut self,
|
||||
size: Size<u32>,
|
||||
scale_factor: f32,
|
||||
background_color: Color,
|
||||
) -> Vec<u8> {
|
||||
let viewport =
|
||||
Viewport::with_physical_size(size, f64::from(scale_factor));
|
||||
|
||||
window::compositor::screenshot(self, &viewport, background_color)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,7 +169,13 @@ impl Pipeline {
|
|||
font_system.raw(),
|
||||
&mut self.glyph_cache,
|
||||
buffer,
|
||||
Rectangle::new(position, Size::new(width, height)),
|
||||
Rectangle::new(
|
||||
position,
|
||||
Size::new(
|
||||
width.unwrap_or(pixels.width() as f32),
|
||||
height.unwrap_or(pixels.height() as f32),
|
||||
),
|
||||
),
|
||||
color,
|
||||
alignment::Horizontal::Left,
|
||||
alignment::Vertical::Top,
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
use crate::core::svg::{Data, Handle};
|
||||
use crate::core::{Color, Rectangle, Size};
|
||||
use crate::graphics::text;
|
||||
|
||||
use resvg::usvg::{self, TreeTextToPath};
|
||||
use resvg::usvg;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use tiny_skia::Transform;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::collections::hash_map;
|
||||
use std::fs;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Pipeline {
|
||||
|
|
@ -69,6 +69,7 @@ struct Cache {
|
|||
tree_hits: FxHashSet<u64>,
|
||||
rasters: FxHashMap<RasterKey, tiny_skia::Pixmap>,
|
||||
raster_hits: FxHashSet<RasterKey>,
|
||||
fontdb: Option<Arc<usvg::fontdb::Database>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
|
|
@ -80,35 +81,37 @@ struct RasterKey {
|
|||
|
||||
impl Cache {
|
||||
fn load(&mut self, handle: &Handle) -> Option<&usvg::Tree> {
|
||||
use usvg::TreeParsing;
|
||||
|
||||
let id = handle.id();
|
||||
|
||||
// TODO: Reuse `cosmic-text` font database
|
||||
if self.fontdb.is_none() {
|
||||
let mut fontdb = usvg::fontdb::Database::new();
|
||||
fontdb.load_system_fonts();
|
||||
|
||||
self.fontdb = Some(Arc::new(fontdb));
|
||||
}
|
||||
|
||||
let options = usvg::Options {
|
||||
fontdb: self
|
||||
.fontdb
|
||||
.as_ref()
|
||||
.expect("fontdb must be initialized")
|
||||
.clone(),
|
||||
..usvg::Options::default()
|
||||
};
|
||||
|
||||
if let hash_map::Entry::Vacant(entry) = self.trees.entry(id) {
|
||||
let mut svg = match handle.data() {
|
||||
let svg = match handle.data() {
|
||||
Data::Path(path) => {
|
||||
fs::read_to_string(path).ok().and_then(|contents| {
|
||||
usvg::Tree::from_str(
|
||||
&contents,
|
||||
&usvg::Options::default(),
|
||||
)
|
||||
.ok()
|
||||
usvg::Tree::from_str(&contents, &options).ok()
|
||||
})
|
||||
}
|
||||
Data::Bytes(bytes) => {
|
||||
usvg::Tree::from_data(bytes, &usvg::Options::default()).ok()
|
||||
usvg::Tree::from_data(bytes, &options).ok()
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -118,11 +121,9 @@ impl Cache {
|
|||
|
||||
fn viewport_dimensions(&mut self, handle: &Handle) -> Option<Size<u32>> {
|
||||
let tree = self.load(handle)?;
|
||||
let size = tree.size();
|
||||
|
||||
Some(Size::new(
|
||||
tree.size.width() as u32,
|
||||
tree.size.height() as u32,
|
||||
))
|
||||
Some(Size::new(size.width() as u32, size.height() as u32))
|
||||
}
|
||||
|
||||
fn draw(
|
||||
|
|
@ -147,7 +148,7 @@ impl Cache {
|
|||
|
||||
let mut image = tiny_skia::Pixmap::new(size.width, size.height)?;
|
||||
|
||||
let tree_size = tree.size.to_int_size();
|
||||
let tree_size = tree.size().to_int_size();
|
||||
|
||||
let target_size = if size.width > size.height {
|
||||
tree_size.scale_to_width(size.width)
|
||||
|
|
@ -167,7 +168,7 @@ impl Cache {
|
|||
tiny_skia::Transform::default()
|
||||
};
|
||||
|
||||
resvg::Tree::from_usvg(tree).render(transform, &mut image.as_mut());
|
||||
resvg::render(tree, transform, &mut image.as_mut());
|
||||
|
||||
if let Some([r, g, b, _]) = key.color {
|
||||
// Apply color filter
|
||||
|
|
|
|||
|
|
@ -120,11 +120,10 @@ impl crate::graphics::Compositor for Compositor {
|
|||
fn screenshot(
|
||||
&mut self,
|
||||
renderer: &mut Self::Renderer,
|
||||
surface: &mut Self::Surface,
|
||||
viewport: &Viewport,
|
||||
background_color: Color,
|
||||
) -> Vec<u8> {
|
||||
screenshot(renderer, surface, viewport, background_color)
|
||||
screenshot(renderer, viewport, background_color)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -208,7 +207,6 @@ pub fn present(
|
|||
|
||||
pub fn screenshot(
|
||||
renderer: &mut Renderer,
|
||||
surface: &mut Surface,
|
||||
viewport: &Viewport,
|
||||
background_color: Color,
|
||||
) -> Vec<u8> {
|
||||
|
|
@ -217,6 +215,9 @@ pub fn screenshot(
|
|||
let mut offscreen_buffer: Vec<u32> =
|
||||
vec![0; size.width as usize * size.height as usize];
|
||||
|
||||
let mut clip_mask = tiny_skia::Mask::new(size.width, size.height)
|
||||
.expect("Create clip mask");
|
||||
|
||||
renderer.draw(
|
||||
&mut tiny_skia::PixmapMut::from_bytes(
|
||||
bytemuck::cast_slice_mut(&mut offscreen_buffer),
|
||||
|
|
@ -224,7 +225,7 @@ pub fn screenshot(
|
|||
size.height,
|
||||
)
|
||||
.expect("Create offscreen pixel map"),
|
||||
&mut surface.clip_mask,
|
||||
&mut clip_mask,
|
||||
viewport,
|
||||
&[Rectangle::with_size(Size::new(
|
||||
size.width as f32,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue