diff --git a/src/decoder/formats/glycin_proxy.rs b/src/decoder/formats/glycin_proxy.rs index 5411afb..e6e142d 100644 --- a/src/decoder/formats/glycin_proxy.rs +++ b/src/decoder/formats/glycin_proxy.rs @@ -16,13 +16,13 @@ // SPDX-License-Identifier: GPL-3.0-or-later //! Decode using glycin + use std::sync::Arc; -use arc_swap::ArcSwap; use gtk::prelude::*; use super::*; -use crate::decoder::tiling::{self, FrameBufferExt}; +use crate::decoder::tiling::{self, SharedFrameBuffer}; use crate::deps::*; use crate::metadata::{ImageFormat, Metadata}; @@ -41,11 +41,7 @@ impl Drop for Glycin { } impl Glycin { - pub fn new( - file: gio::File, - updater: UpdateSender, - tiles: Arc>, - ) -> Self { + pub fn new(file: gio::File, updater: UpdateSender, tiles: Arc) -> Self { let cancellable = gio::Cancellable::new(); let cancellable_ = cancellable.clone(); diff --git a/src/decoder/formats/svg.rs b/src/decoder/formats/svg.rs index 02c3482..04dc372 100644 --- a/src/decoder/formats/svg.rs +++ b/src/decoder/formats/svg.rs @@ -16,15 +16,15 @@ // SPDX-License-Identifier: GPL-3.0-or-later //! Decode using librsvg + use std::sync::Arc; use anyhow::Context; -use arc_swap::ArcSwap; use async_channel as mpsc; use gtk::prelude::*; use super::*; -use crate::decoder::tiling::{self, FrameBufferExt}; +use crate::decoder::tiling::SharedFrameBuffer; use crate::decoder::TileRequest; use crate::deps::*; use crate::metadata::ImageFormat; @@ -61,11 +61,7 @@ impl Drop for Svg { } impl Svg { - pub fn new( - file: gio::File, - updater: UpdateSender, - tiles: Arc>, - ) -> Self { + pub fn new(file: gio::File, updater: UpdateSender, tiles: Arc) -> Self { let current_request: Arc> = Default::default(); let request_store = current_request.clone(); let cancellable = gio::Cancellable::new(); diff --git a/src/decoder/mod.rs b/src/decoder/mod.rs index f561dd7..ac32b18 100644 --- a/src/decoder/mod.rs +++ b/src/decoder/mod.rs @@ -17,18 +17,18 @@ // SPDX-License-Identifier: GPL-3.0-or-later //! Decodes several image formats + pub mod formats; pub mod tiling; use std::sync::Arc; use anyhow::Result; -use arc_swap::ArcSwap; use formats::*; pub use formats::{ImageDimensionDetails, RSVG_MAX_SIZE}; use futures_channel::mpsc; -use tiling::FrameBufferExt; +use self::tiling::SharedFrameBuffer; use crate::deps::*; use crate::metadata::{ImageFormat, Metadata}; @@ -117,7 +117,7 @@ impl Decoder { pub async fn new( file: gio::File, mime_type: Option, - tiles: Arc>, + tiles: Arc, ) -> (Self, mpsc::UnboundedReceiver) { let (sender, receiver) = mpsc::unbounded(); @@ -137,7 +137,7 @@ impl Decoder { update_sender: UpdateSender, file: gio::File, mime_type: Option, - tiles: Arc>, + tiles: Arc, ) -> FormatDecoder { if let Some(mime_type) = mime_type { // Known things we want to match here are diff --git a/src/decoder/tiling.rs b/src/decoder/tiling.rs index 9c6df76..ee31063 100644 --- a/src/decoder/tiling.rs +++ b/src/decoder/tiling.rs @@ -572,78 +572,68 @@ impl RectExt for graphene::Rect { } } -/// We always store [`FrameBuffer`]s in an [`ArcSwap`]. -/// This trait adds convenience functions for this. -pub trait FrameBufferExt { - fn push(&self, tile: Tile); - fn push_tile(&self, tiling: Tiling, position: Coordinates, texture: gdk::Texture); - fn push_frame(&self, tile: Tile, dimensions: Coordinates, delay: Duration); - fn reset(&self); - fn get_layer_tiling_or_default(&self, zoom: f64, viewport: graphene::Rect) -> Tiling; - /// Return true if the next frame should be shown and removes the outdated - /// frame - fn frame_timeout(&self, elapsed: Duration) -> bool; - fn next_frame(&self); - /// Returns the number of currently buffered frames - fn n_frames(&self) -> usize; - fn set_original_dimensions(&self, size: Coordinates); - fn set_original_dimensions_full( - &self, - size: Coordinates, - dimension_details: ImageDimensionDetails, - ); - fn set_update_sender(&self, sender: UpdateSender); +#[derive(Debug, Default)] +pub struct SharedFrameBuffer { + buffer: ArcSwap, } -impl FrameBufferExt for ArcSwap { - fn push(&self, tile: Tile) { - self.rcu(|tiling_store| { +impl std::ops::Deref for SharedFrameBuffer { + type Target = ArcSwap; + + fn deref(&self) -> &Self::Target { + &self.buffer + } +} + +impl SharedFrameBuffer { + pub fn push(&self, tile: Tile) { + self.buffer.rcu(|tiling_store| { let mut new_store = (**tiling_store).clone(); new_store.current().push(tile.clone()); Arc::new(new_store) }); - if let Some(updater) = &self.load().update_sender { + if let Some(updater) = &self.buffer.load().update_sender { updater.send(DecoderUpdate::Redraw); } } - fn push_tile(&self, tiling: Tiling, position: Coordinates, texture: gdk::Texture) { - self.rcu(|tiling_store| { + pub fn push_tile(&self, tiling: Tiling, position: Coordinates, texture: gdk::Texture) { + self.buffer.rcu(|tiling_store| { let mut new_store = (**tiling_store).clone(); new_store .current() .push_tile(tiling, position, texture.clone()); Arc::new(new_store) }); - if let Some(updater) = &self.load().update_sender { + if let Some(updater) = &self.buffer.load().update_sender { updater.send(DecoderUpdate::Redraw); } } - fn push_frame(&self, tile: Tile, dimensions: Coordinates, delay: Duration) { + pub fn push_frame(&self, tile: Tile, dimensions: Coordinates, delay: Duration) { let mut store = TiledImage::default(); store.push(tile); store.original_dimensions = Some(dimensions); store.delay = delay; - self.rcu(|tiling_store| { + self.buffer.rcu(|tiling_store| { let mut new_store = (**tiling_store).clone(); new_store.images.push_back(store.clone()); Arc::new(new_store) }); } - fn reset(&self) { - self.rcu(|tiling_store| { + pub fn reset(&self) { + self.buffer.rcu(|tiling_store| { let mut new_store = (**tiling_store).clone(); new_store.reset(); Arc::new(new_store) }); } - fn get_layer_tiling_or_default(&self, zoom: f64, viewport: graphene::Rect) -> Tiling { + pub fn get_layer_tiling_or_default(&self, zoom: f64, viewport: graphene::Rect) -> Tiling { let mut tiling = None; - self.rcu(|tiling_store| { + self.buffer.rcu(|tiling_store| { let mut new_store = (**tiling_store).clone(); tiling = Some( new_store @@ -655,8 +645,11 @@ impl FrameBufferExt for ArcSwap { tiling.unwrap() } - fn frame_timeout(&self, elapsed: Duration) -> bool { + /// Return true if the next frame should be shown and removes the outdated + /// frame + pub fn frame_timeout(&self, elapsed: Duration) -> bool { if self + .buffer .load() .images .front() @@ -669,40 +662,41 @@ impl FrameBufferExt for ArcSwap { false } - fn next_frame(&self) { - self.rcu(|tiling_store| { + pub fn next_frame(&self) { + self.buffer.rcu(|tiling_store| { let mut new_store = (**tiling_store).clone(); new_store.images.pop_front(); Arc::new(new_store) }); } - fn n_frames(&self) -> usize { - self.load().images.len() + /// Returns the number of currently buffered frames + pub fn n_frames(&self) -> usize { + self.buffer.load().images.len() } - fn set_original_dimensions(&self, size: Coordinates) { + pub fn set_original_dimensions(&self, size: Coordinates) { self.set_original_dimensions_full(size, Default::default()); } - fn set_original_dimensions_full( + pub fn set_original_dimensions_full( &self, size: Coordinates, dimension_details: ImageDimensionDetails, ) { - self.rcu(|tiling_store| { + self.buffer.rcu(|tiling_store| { let mut new_store = (**tiling_store).clone(); new_store.current().original_dimensions = Some(size); Arc::new(new_store) }); - if let Some(updater) = &self.load().update_sender { + if let Some(updater) = &self.buffer.load().update_sender { updater.send(DecoderUpdate::Dimensions(dimension_details)); } } - fn set_update_sender(&self, sender: UpdateSender) { - self.rcu(|tiling_store| { + pub fn set_update_sender(&self, sender: UpdateSender) { + self.buffer.rcu(|tiling_store| { let mut new_store = (**tiling_store).clone(); new_store.set_update_sender(sender.clone()); Arc::new(new_store) diff --git a/src/widgets/image.rs b/src/widgets/image.rs index 7eff3cb..f35d2ff 100644 --- a/src/widgets/image.rs +++ b/src/widgets/image.rs @@ -48,13 +48,11 @@ use std::sync::Arc; use adw::prelude::*; use adw::subclass::prelude::*; -use arc_swap::ArcSwap; use futures_lite::StreamExt; use glib::subclass::Signal; use glib::{Properties, SignalGroup}; use once_cell::sync::Lazy; -use crate::decoder::tiling::FrameBufferExt; use crate::decoder::{self, tiling, Decoder, DecoderUpdate}; use crate::deps::*; use crate::metadata::Metadata; @@ -126,6 +124,7 @@ pub enum FitMode { mod imp { use super::*; + use crate::decoder::tiling::SharedFrameBuffer; #[derive(Debug, Default, Properties)] #[properties(wrapper_type = super::LpImage)] @@ -148,7 +147,7 @@ mod imp { /// Track changes to this image pub(super) file_monitor: RefCell>, - pub(super) frame_buffer: Arc>, + pub(super) frame_buffer: Arc, pub(super) decoder: RefCell>>, /// Rotation final value (can differ from `rotation` during animation) diff --git a/src/widgets/print_preview.rs b/src/widgets/print_preview.rs index d5cb285..2653f81 100644 --- a/src/widgets/print_preview.rs +++ b/src/widgets/print_preview.rs @@ -23,11 +23,10 @@ use adw::subclass::prelude::*; use glib::Properties; use gtk::prelude::*; +use super::image; use crate::deps::*; use crate::widgets::LpPrint; -use super::image; - mod imp_page { use super::*;