From 9a3c81f336b8e29c64471026860f3c9d8b56348c Mon Sep 17 00:00:00 2001
From: Héctor Ramón Jiménez <hector0193@gmail.com>
Date: Sun, 31 Oct 2021 16:24:31 +0700
Subject: Introduce first-class `svg` module in `iced_native`

---
 glow/src/backend.rs        |  2 +-
 graphics/src/backend.rs    |  2 +-
 graphics/src/primitive.rs  |  2 +-
 graphics/src/widget/svg.rs |  5 ++-
 native/src/lib.rs          |  1 +
 native/src/svg.rs          | 90 ++++++++++++++++++++++++++++++++++++++++++++
 native/src/widget/svg.rs   | 93 ++--------------------------------------------
 src/widget.rs              |  3 +-
 wgpu/src/backend.rs        |  2 +-
 wgpu/src/image.rs          |  2 +-
 wgpu/src/image/vector.rs   |  2 +-
 11 files changed, 106 insertions(+), 98 deletions(-)
 create mode 100644 native/src/svg.rs

diff --git a/glow/src/backend.rs b/glow/src/backend.rs
index 337d2e17..5ab7f922 100644
--- a/glow/src/backend.rs
+++ b/glow/src/backend.rs
@@ -246,7 +246,7 @@ impl backend::Image for Backend {
 impl backend::Svg for Backend {
     fn viewport_dimensions(
         &self,
-        _handle: &iced_native::widget::svg::Handle,
+        _handle: &iced_native::svg::Handle,
     ) -> (u32, u32) {
         (50, 50)
     }
diff --git a/graphics/src/backend.rs b/graphics/src/backend.rs
index e9f3801a..b8ff5d21 100644
--- a/graphics/src/backend.rs
+++ b/graphics/src/backend.rs
@@ -1,7 +1,7 @@
 //! Write a graphics backend.
 use iced_native::image;
+use iced_native::svg;
 use iced_native::text;
-use iced_native::widget::svg;
 use iced_native::{Font, Point, Size};
 
 /// The graphics backend of a [`Renderer`].
diff --git a/graphics/src/primitive.rs b/graphics/src/primitive.rs
index c46c212e..5f7a344d 100644
--- a/graphics/src/primitive.rs
+++ b/graphics/src/primitive.rs
@@ -1,5 +1,5 @@
 use iced_native::image;
-use iced_native::widget::svg;
+use iced_native::svg;
 use iced_native::{Background, Color, Font, Rectangle, Size, Vector};
 
 use crate::alignment;
diff --git a/graphics/src/widget/svg.rs b/graphics/src/widget/svg.rs
index 64a2b461..5817a552 100644
--- a/graphics/src/widget/svg.rs
+++ b/graphics/src/widget/svg.rs
@@ -1,9 +1,10 @@
 //! Display vector graphics in your application.
 use crate::backend::{self, Backend};
 use crate::{Primitive, Rectangle, Renderer};
-use iced_native::widget::svg;
+use iced_native::svg;
 
-pub use iced_native::widget::svg::{Handle, Svg};
+pub use iced_native::widget::svg::Svg;
+pub use svg::Handle;
 
 impl<B> svg::Renderer for Renderer<B>
 where
diff --git a/native/src/lib.rs b/native/src/lib.rs
index 704a9873..5012b3f4 100644
--- a/native/src/lib.rs
+++ b/native/src/lib.rs
@@ -44,6 +44,7 @@ pub mod overlay;
 pub mod program;
 pub mod renderer;
 pub mod subscription;
+pub mod svg;
 pub mod text;
 pub mod touch;
 pub mod widget;
diff --git a/native/src/svg.rs b/native/src/svg.rs
new file mode 100644
index 00000000..229738ee
--- /dev/null
+++ b/native/src/svg.rs
@@ -0,0 +1,90 @@
+use crate::{Hasher, Rectangle};
+
+use std::hash::{Hash, Hasher as _};
+use std::path::PathBuf;
+use std::sync::Arc;
+
+/// An [`Svg`] handle.
+#[derive(Debug, Clone)]
+pub struct Handle {
+    id: u64,
+    data: Arc<Data>,
+}
+
+impl Handle {
+    /// Creates an SVG [`Handle`] pointing to the vector image of the given
+    /// path.
+    pub fn from_path(path: impl Into<PathBuf>) -> Handle {
+        Self::from_data(Data::Path(path.into()))
+    }
+
+    /// Creates an SVG [`Handle`] from raw bytes containing either an SVG string
+    /// or gzip compressed data.
+    ///
+    /// This is useful if you already have your SVG data in-memory, maybe
+    /// because you downloaded or generated it procedurally.
+    pub fn from_memory(bytes: impl Into<Vec<u8>>) -> Handle {
+        Self::from_data(Data::Bytes(bytes.into()))
+    }
+
+    fn from_data(data: Data) -> Handle {
+        let mut hasher = Hasher::default();
+        data.hash(&mut hasher);
+
+        Handle {
+            id: hasher.finish(),
+            data: Arc::new(data),
+        }
+    }
+
+    /// Returns the unique identifier of the [`Handle`].
+    pub fn id(&self) -> u64 {
+        self.id
+    }
+
+    /// Returns a reference to the SVG [`Data`].
+    pub fn data(&self) -> &Data {
+        &self.data
+    }
+}
+
+impl Hash for Handle {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        self.id.hash(state);
+    }
+}
+
+/// The data of an [`Svg`].
+#[derive(Clone, Hash)]
+pub enum Data {
+    /// File data
+    Path(PathBuf),
+
+    /// In-memory data
+    ///
+    /// Can contain an SVG string or a gzip compressed data.
+    Bytes(Vec<u8>),
+}
+
+impl std::fmt::Debug for Data {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Data::Path(path) => write!(f, "Path({:?})", path),
+            Data::Bytes(_) => write!(f, "Bytes(...)"),
+        }
+    }
+}
+
+/// The renderer of an [`Svg`].
+///
+/// Your [renderer] will need to implement this trait before being able to use
+/// an [`Svg`] in your user interface.
+///
+/// [renderer]: crate::renderer
+pub trait Renderer: crate::Renderer {
+    /// Returns the default dimensions of an [`Svg`] for the given [`Handle`].
+    fn dimensions(&self, handle: &Handle) -> (u32, u32);
+
+    // Draws an [`Svg`].
+    fn draw(&mut self, handle: Handle, bounds: Rectangle);
+}
diff --git a/native/src/widget/svg.rs b/native/src/widget/svg.rs
index 785b8054..f212dfcb 100644
--- a/native/src/widget/svg.rs
+++ b/native/src/widget/svg.rs
@@ -1,11 +1,11 @@
 //! Display vector graphics in your application.
 use crate::layout;
 use crate::renderer;
+use crate::svg::{self, Handle};
 use crate::{Element, Hasher, Layout, Length, Point, Rectangle, Size, Widget};
 
-use std::hash::{Hash, Hasher as _};
+use std::hash::Hash;
 use std::path::PathBuf;
-use std::sync::Arc;
 
 /// A vector graphics image.
 ///
@@ -51,7 +51,7 @@ impl Svg {
 
 impl<Message, Renderer> Widget<Message, Renderer> for Svg
 where
-    Renderer: self::Renderer,
+    Renderer: svg::Renderer,
 {
     fn width(&self) -> Length {
         self.width
@@ -106,94 +106,9 @@ where
     }
 }
 
-/// An [`Svg`] handle.
-#[derive(Debug, Clone)]
-pub struct Handle {
-    id: u64,
-    data: Arc<Data>,
-}
-
-impl Handle {
-    /// Creates an SVG [`Handle`] pointing to the vector image of the given
-    /// path.
-    pub fn from_path(path: impl Into<PathBuf>) -> Handle {
-        Self::from_data(Data::Path(path.into()))
-    }
-
-    /// Creates an SVG [`Handle`] from raw bytes containing either an SVG string
-    /// or gzip compressed data.
-    ///
-    /// This is useful if you already have your SVG data in-memory, maybe
-    /// because you downloaded or generated it procedurally.
-    pub fn from_memory(bytes: impl Into<Vec<u8>>) -> Handle {
-        Self::from_data(Data::Bytes(bytes.into()))
-    }
-
-    fn from_data(data: Data) -> Handle {
-        let mut hasher = Hasher::default();
-        data.hash(&mut hasher);
-
-        Handle {
-            id: hasher.finish(),
-            data: Arc::new(data),
-        }
-    }
-
-    /// Returns the unique identifier of the [`Handle`].
-    pub fn id(&self) -> u64 {
-        self.id
-    }
-
-    /// Returns a reference to the SVG [`Data`].
-    pub fn data(&self) -> &Data {
-        &self.data
-    }
-}
-
-impl Hash for Handle {
-    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
-        self.id.hash(state);
-    }
-}
-
-/// The data of an [`Svg`].
-#[derive(Clone, Hash)]
-pub enum Data {
-    /// File data
-    Path(PathBuf),
-
-    /// In-memory data
-    ///
-    /// Can contain an SVG string or a gzip compressed data.
-    Bytes(Vec<u8>),
-}
-
-impl std::fmt::Debug for Data {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            Data::Path(path) => write!(f, "Path({:?})", path),
-            Data::Bytes(_) => write!(f, "Bytes(...)"),
-        }
-    }
-}
-
-/// The renderer of an [`Svg`].
-///
-/// Your [renderer] will need to implement this trait before being able to use
-/// an [`Svg`] in your user interface.
-///
-/// [renderer]: crate::renderer
-pub trait Renderer: crate::Renderer {
-    /// Returns the default dimensions of an [`Svg`] for the given [`Handle`].
-    fn dimensions(&self, handle: &Handle) -> (u32, u32);
-
-    // Draws an [`Svg`].
-    fn draw(&mut self, handle: Handle, bounds: Rectangle);
-}
-
 impl<'a, Message, Renderer> From<Svg> for Element<'a, Message, Renderer>
 where
-    Renderer: self::Renderer,
+    Renderer: svg::Renderer,
 {
     fn from(icon: Svg) -> Element<'a, Message, Renderer> {
         Element::new(icon)
diff --git a/src/widget.rs b/src/widget.rs
index f2bd18cf..0f0b0325 100644
--- a/src/widget.rs
+++ b/src/widget.rs
@@ -46,7 +46,8 @@ mod platform {
     #[cfg_attr(docsrs, doc(cfg(feature = "svg")))]
     pub mod svg {
         //! Display vector graphics in your user interface.
-        pub use crate::runtime::widget::svg::{Handle, Svg};
+        pub use crate::runtime::svg::Handle;
+        pub use crate::runtime::widget::svg::Svg;
     }
 
     #[doc(no_inline)]
diff --git a/wgpu/src/backend.rs b/wgpu/src/backend.rs
index 0f4c35c3..bb84cc8f 100644
--- a/wgpu/src/backend.rs
+++ b/wgpu/src/backend.rs
@@ -311,7 +311,7 @@ impl backend::Image for Backend {
 impl backend::Svg for Backend {
     fn viewport_dimensions(
         &self,
-        handle: &iced_native::widget::svg::Handle,
+        handle: &iced_native::svg::Handle,
     ) -> (u32, u32) {
         self.image_pipeline.viewport_dimensions(handle)
     }
diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs
index 01af2571..a59dc04b 100644
--- a/wgpu/src/image.rs
+++ b/wgpu/src/image.rs
@@ -20,7 +20,7 @@ use bytemuck::{Pod, Zeroable};
 use iced_native::image;
 
 #[cfg(feature = "svg")]
-use iced_native::widget::svg;
+use iced_native::svg;
 
 #[derive(Debug)]
 pub struct Pipeline {
diff --git a/wgpu/src/image/vector.rs b/wgpu/src/image/vector.rs
index edf339f5..4c830913 100644
--- a/wgpu/src/image/vector.rs
+++ b/wgpu/src/image/vector.rs
@@ -1,6 +1,6 @@
 use crate::image::atlas::{self, Atlas};
 
-use iced_native::widget::svg;
+use iced_native::svg;
 
 use std::collections::{HashMap, HashSet};
 use std::fs;
-- 
cgit