Detailed changes
@@ -1,5 +1,11 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
[[package]]
name = "adler32"
version = "1.2.0"
@@ -297,6 +303,12 @@ version = "3.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe"
+[[package]]
+name = "bytemuck"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bed57e2090563b83ba8f83366628ce535a7584c9afa4c9fc0612a03925c6df58"
+
[[package]]
name = "byteorder"
version = "1.4.2"
@@ -545,6 +557,15 @@ dependencies = [
"syn",
]
+[[package]]
+name = "data-url"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d33fe99ccedd6e84bc035f1931bb2e6be79739d6242bd895e7311c886c50dc9c"
+dependencies = [
+ "matches",
+]
+
[[package]]
name = "deflate"
version = "0.8.6"
@@ -671,6 +692,24 @@ dependencies = [
"instant",
]
+[[package]]
+name = "flate2"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0"
+dependencies = [
+ "cfg-if 1.0.0",
+ "crc32fast",
+ "libc",
+ "miniz_oxide 0.4.4",
+]
+
+[[package]]
+name = "float-cmp"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75224bec9bfe1a65e2d34132933f2de7fe79900c96a0174307554244ece8150e"
+
[[package]]
name = "float-ord"
version = "0.2.0"
@@ -707,6 +746,17 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "fontdb"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "428948a0f39fb83fe55991d4423e35a793cdbb0322ebe23853f6024124a330d7"
+dependencies = [
+ "log",
+ "memmap2 0.1.0",
+ "ttf-parser 0.9.0",
+]
+
[[package]]
name = "foreign-types"
version = "0.3.2"
@@ -879,10 +929,13 @@ dependencies = [
"png",
"rand 0.8.3",
"replace_with",
+ "resvg",
"simplelog",
"smallvec",
"smol",
+ "tiny-skia",
"tree-sitter",
+ "usvg",
]
[[package]]
@@ -933,6 +986,12 @@ version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
+[[package]]
+name = "jpeg-decoder"
+version = "0.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2"
+
[[package]]
name = "js-sys"
version = "0.3.50"
@@ -942,6 +1001,15 @@ dependencies = [
"wasm-bindgen",
]
+[[package]]
+name = "kurbo"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e30b1df631d23875f230ed3ddd1a88c231f269a04b2044eb6ca87e763b5f4c42"
+dependencies = [
+ "arrayvec",
+]
+
[[package]]
name = "kv-log-macro"
version = "1.0.7"
@@ -1018,6 +1086,12 @@ dependencies = [
"libc",
]
+[[package]]
+name = "matches"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
+
[[package]]
name = "maybe-uninit"
version = "2.0.0"
@@ -1030,6 +1104,24 @@ version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
+[[package]]
+name = "memmap2"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b70ca2a6103ac8b665dc150b142ef0e4e89df640c9e6cf295d189c3caebe5a"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "memmap2"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "397d1a6d6d0563c0f5462bbdae662cf6c784edf5e828e40c7257f85d82bf56dd"
+dependencies = [
+ "libc",
+]
+
[[package]]
name = "metal"
version = "0.21.0"
@@ -1053,6 +1145,16 @@ dependencies = [
"adler32",
]
+[[package]]
+name = "miniz_oxide"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
+dependencies = [
+ "adler",
+ "autocfg",
+]
+
[[package]]
name = "nb-connect"
version = "1.0.3"
@@ -1201,6 +1303,12 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
+[[package]]
+name = "pico-args"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d70072c20945e1ab871c472a285fc772aefd4f5407723c206242f2c6f94595d6"
+
[[package]]
name = "pin-project-lite"
version = "0.2.4"
@@ -1228,7 +1336,7 @@ dependencies = [
"bitflags",
"crc32fast",
"deflate",
- "miniz_oxide",
+ "miniz_oxide 0.3.7",
]
[[package]]
@@ -1336,6 +1444,12 @@ dependencies = [
"rand_core 0.6.2",
]
+[[package]]
+name = "rctree"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be9e29cb19c8fe84169fcb07f8f11e66bc9e6e0280efd4715c54818296f8a4a8"
+
[[package]]
name = "rdrand"
version = "0.4.0"
@@ -1414,6 +1528,40 @@ version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3a8614ee435691de62bcffcf4a66d91b3594bf1428a5722e79103249a095690"
+[[package]]
+name = "resvg"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac9efbe9c239253e11e518352c5f015ec0c69e73658eed153670e853e1b78e40"
+dependencies = [
+ "jpeg-decoder",
+ "log",
+ "pico-args",
+ "png",
+ "rgb",
+ "svgfilters",
+ "tiny-skia",
+ "usvg",
+]
+
+[[package]]
+name = "rgb"
+version = "0.8.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fddb3b23626145d1776addfc307e1a1851f60ef6ca64f376bcb889697144cf0"
+dependencies = [
+ "bytemuck",
+]
+
+[[package]]
+name = "roxmltree"
+version = "0.14.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "921904a62e410e37e215c40381b7117f830d9d89ba60ab5236170541dd25646b"
+dependencies = [
+ "xmlparser",
+]
+
[[package]]
name = "rust-argon2"
version = "0.8.3"
@@ -1474,12 +1622,37 @@ dependencies = [
"semver",
]
+[[package]]
+name = "rustybuzz"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ab463a295d00f3692e0974a0bfd83c7a9bcd119e27e07c2beecdb1b44a09d10"
+dependencies = [
+ "bitflags",
+ "bytemuck",
+ "smallvec",
+ "ttf-parser 0.9.0",
+ "unicode-bidi-mirroring",
+ "unicode-ccc",
+ "unicode-general-category",
+ "unicode-script",
+]
+
[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
+[[package]]
+name = "safe_arch"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1ff3d6d9696af502cc3110dacce942840fb06ff4514cad92236ecc455f2ce05"
+dependencies = [
+ "bytemuck",
+]
+
[[package]]
name = "same-file"
version = "1.0.6"
@@ -1579,6 +1752,15 @@ dependencies = [
"libc",
]
+[[package]]
+name = "simplecss"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "596554e63596d556a0dbd681416342ca61c75f1a45203201e7e77d3fa2fa9014"
+dependencies = [
+ "log",
+]
+
[[package]]
name = "simplelog"
version = "0.9.0"
@@ -1590,6 +1772,12 @@ dependencies = [
"termcolor",
]
+[[package]]
+name = "siphasher"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
+
[[package]]
name = "slab"
version = "0.4.2"
@@ -1643,6 +1831,26 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fb1df15f412ee2e9dfc1c504260fa695c1c3f10fe9f4a6ee2d2184d7d6450e2"
+[[package]]
+name = "svgfilters"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb0dce2fee79ac40c21dafba48565ff7a5fa275e23ffe9ce047a40c9574ba34e"
+dependencies = [
+ "float-cmp",
+ "rgb",
+]
+
+[[package]]
+name = "svgtypes"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c536faaff1a10837cfe373142583f6e27d81e96beba339147e77b67c9f260ff"
+dependencies = [
+ "float-cmp",
+ "siphasher",
+]
+
[[package]]
name = "syn"
version = "1.0.67"
@@ -1702,6 +1910,20 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "tiny-skia"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bf81f2900d2e235220e6f31ec9f63ade6a7f59090c556d74fe949bb3b15e9fe"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "bytemuck",
+ "cfg-if 1.0.0",
+ "png",
+ "safe_arch",
+]
+
[[package]]
name = "tree-sitter"
version = "0.17.1"
@@ -1712,6 +1934,57 @@ dependencies = [
"regex",
]
+[[package]]
+name = "ttf-parser"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62ddb402ac6c2af6f7a2844243887631c4e94b51585b229fcfddb43958cd55ca"
+
+[[package]]
+name = "ttf-parser"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85e00391c1f3d171490a3f8bd79999b0002ae38d3da0d6a3a306c754b053d71b"
+
+[[package]]
+name = "unicode-bidi"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
+dependencies = [
+ "matches",
+]
+
+[[package]]
+name = "unicode-bidi-mirroring"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56d12260fb92d52f9008be7e4bca09f584780eb2266dc8fecc6a192bec561694"
+
+[[package]]
+name = "unicode-ccc"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28ae07c514c335bbd0251147bb1de333e28ebc8f57d792014f919ed212d119f6"
+
+[[package]]
+name = "unicode-general-category"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f9af028e052a610d99e066b33304625dea9613170a2563314490a4e6ec5cf7f"
+
+[[package]]
+name = "unicode-script"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79bf4d5fc96546fdb73f9827097810bbda93b11a6770ff3a54e1f445d4135787"
+
+[[package]]
+name = "unicode-vo"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94"
+
[[package]]
name = "unicode-width"
version = "0.1.8"
@@ -1730,6 +2003,33 @@ version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7"
+[[package]]
+name = "usvg"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ffbeb91d06989028c9c5e44d14d78b0cacdec56a613bb146e7a70007b1b6163"
+dependencies = [
+ "base64",
+ "data-url",
+ "flate2",
+ "fontdb",
+ "kurbo",
+ "log",
+ "memmap2 0.2.2",
+ "pico-args",
+ "rctree",
+ "roxmltree",
+ "rustybuzz",
+ "simplecss",
+ "siphasher",
+ "svgtypes",
+ "ttf-parser 0.12.0",
+ "unicode-bidi",
+ "unicode-script",
+ "unicode-vo",
+ "xmlwriter",
+]
+
[[package]]
name = "value-bag"
version = "1.0.0-alpha.6"
@@ -1920,6 +2220,18 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "xmlparser"
+version = "0.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "114ba2b24d2167ef6d67d7d04c8cc86522b87f490025f39f0303b7db5bf5e3d8"
+
+[[package]]
+name = "xmlwriter"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
+
[[package]]
name = "zed"
version = "0.1.0"
@@ -17,9 +17,12 @@ pathfinder_color = "0.5"
pathfinder_geometry = "0.5"
rand = "0.8.3"
replace_with = "0.1.7"
+resvg = "0.14"
smallvec = "1.6.1"
smol = "1.2"
+tiny-skia = "0.5"
tree-sitter = "0.17"
+usvg = "0.14"
[build-dependencies]
bindgen = "0.57"
@@ -1,5 +1,5 @@
use anyhow::{anyhow, Result};
-use std::borrow::Cow;
+use std::{borrow::Cow, cell::RefCell, collections::HashMap};
pub trait AssetSource: 'static {
fn load(&self, path: &str) -> Result<Cow<[u8]>>;
@@ -16,12 +16,26 @@ impl AssetSource for () {
pub struct AssetCache {
source: Box<dyn AssetSource>,
+ svgs: RefCell<HashMap<String, usvg::Tree>>,
}
impl AssetCache {
pub fn new(source: impl AssetSource) -> Self {
Self {
source: Box::new(source),
+ svgs: RefCell::new(HashMap::new()),
+ }
+ }
+
+ pub fn svg(&self, path: &str) -> Result<usvg::Tree> {
+ let mut svgs = self.svgs.borrow_mut();
+ if let Some(svg) = svgs.get(path) {
+ Ok(svg.clone())
+ } else {
+ let bytes = self.source.load(path)?;
+ let svg = usvg::Tree::from_data(&bytes, &usvg::Options::default())?;
+ svgs.insert(path.to_string(), svg.clone());
+ Ok(svg)
}
}
}
@@ -1,73 +1,85 @@
use crate::{
- geometry::vector::Vector2F, AfterLayoutContext, Element, Event, EventContext, LayoutContext,
- PaintContext, SizeConstraint,
+ color::ColorU,
+ geometry::{
+ rect::RectF,
+ vector::{vec2f, Vector2F},
+ },
+ scene, AfterLayoutContext, Element, Event, EventContext, LayoutContext, PaintContext,
+ SizeConstraint,
};
pub struct Svg {
path: String,
+ color: ColorU,
}
impl Svg {
pub fn new(path: String) -> Self {
- Self { path }
+ Self {
+ path,
+ color: ColorU::black(),
+ }
+ }
+
+ pub fn with_color(mut self, color: ColorU) -> Self {
+ self.color = color;
+ self
}
}
impl Element for Svg {
- type LayoutState = ();
+ type LayoutState = Option<usvg::Tree>;
type PaintState = ();
fn layout(
&mut self,
- _: SizeConstraint,
- _: &mut LayoutContext,
+ constraint: SizeConstraint,
+ ctx: &mut LayoutContext,
) -> (Vector2F, Self::LayoutState) {
- // let size;
- // match ctx.asset_cache.svg(&self.path) {
- // Ok(tree) => {
- // size = if constraint.max.x().is_infinite() && constraint.max.y().is_infinite() {
- // let rect = usvg_rect_to_euclid_rect(&tree.svg_node().view_box.rect);
- // rect.size()
- // } else {
- // let max_size = constraint.max;
- // let svg_size = usvg_rect_to_euclid_rect(&tree.svg_node().view_box.rect).size();
-
- // if max_size.x().is_infinite()
- // || max_size.x() / max_size.y() > svg_size.x() / svg_size.y()
- // {
- // vec2f(svg_size.x() * max_size.y() / svg_size.y(), max_size.y())
- // } else {
- // vec2f(max_size.x(), svg_size.y() * max_size.x() / svg_size.x())
- // }
- // };
- // self.tree = Some(tree);
- // }
- // Err(error) => {
- // log::error!("{}", error);
- // size = constraint.min;
- // }
- // };
-
- // size
+ match ctx.asset_cache.svg(&self.path) {
+ Ok(tree) => {
+ let size = if constraint.max.x().is_infinite() && constraint.max.y().is_infinite() {
+ let rect = from_usvg_rect(tree.svg_node().view_box.rect);
+ rect.size()
+ } else {
+ let max_size = constraint.max;
+ let svg_size = from_usvg_rect(tree.svg_node().view_box.rect).size();
- todo!()
+ if max_size.x().is_infinite()
+ || max_size.x() / max_size.y() > svg_size.x() / svg_size.y()
+ {
+ vec2f(svg_size.x() * max_size.y() / svg_size.y(), max_size.y())
+ } else {
+ vec2f(max_size.x(), svg_size.y() * max_size.x() / svg_size.x())
+ }
+ };
+ (size, Some(tree))
+ }
+ Err(error) => {
+ log::error!("{}", error);
+ (constraint.min, None)
+ }
+ }
}
fn after_layout(&mut self, _: Vector2F, _: &mut Self::LayoutState, _: &mut AfterLayoutContext) {
}
- fn paint(
- &mut self,
- _: pathfinder_geometry::rect::RectF,
- _: &mut Self::LayoutState,
- _: &mut PaintContext,
- ) -> Self::PaintState {
+ fn paint(&mut self, bounds: RectF, svg: &mut Self::LayoutState, ctx: &mut PaintContext) {
+ if let Some(svg) = svg.clone() {
+ ctx.scene.push_icon(scene::Icon {
+ bounds,
+ svg,
+ path: self.path.clone(),
+ color: self.color,
+ });
+ }
}
fn dispatch_event(
&mut self,
_: &Event,
- _: pathfinder_geometry::rect::RectF,
+ _: RectF,
_: &mut Self::LayoutState,
_: &mut Self::PaintState,
_: &mut EventContext,
@@ -75,3 +87,10 @@ impl Element for Svg {
false
}
}
+
+fn from_usvg_rect(rect: usvg::Rect) -> RectF {
+ RectF::new(
+ vec2f(rect.x() as f32, rect.y() as f32),
+ vec2f(rect.width() as f32, rect.height() as f32),
+ )
+}
@@ -296,7 +296,7 @@ impl Renderer {
drawable_size,
command_encoder,
);
- self.render_glyph_sprites(scene, layer, offset, drawable_size, command_encoder);
+ self.render_sprites(scene, layer, offset, drawable_size, command_encoder);
}
command_encoder.end_encoding();
@@ -465,7 +465,7 @@ impl Renderer {
*offset = next_offset;
}
- fn render_glyph_sprites(
+ fn render_sprites(
&mut self,
scene: &Scene,
layer: &Layer,
@@ -473,11 +473,12 @@ impl Renderer {
drawable_size: Vector2F,
command_encoder: &metal::RenderCommandEncoderRef,
) {
- if layer.glyphs().is_empty() {
+ if layer.glyphs().is_empty() && layer.icons().is_empty() {
return;
}
let mut sprites_by_atlas = HashMap::new();
+
for glyph in layer.glyphs() {
if let Some(sprite) = self.sprite_cache.render_glyph(
glyph.font_id,
@@ -501,6 +502,28 @@ impl Renderer {
}
}
+ for icon in layer.icons() {
+ let sprite = self.sprite_cache.render_icon(
+ icon.bounds.size(),
+ icon.path.clone(),
+ icon.svg.clone(),
+ scene.scale_factor(),
+ );
+
+ // Snap sprite to pixel grid.
+ let origin = (icon.bounds.origin() * scene.scale_factor()).floor();
+ sprites_by_atlas
+ .entry(sprite.atlas_id)
+ .or_insert_with(Vec::new)
+ .push(shaders::GPUISprite {
+ origin: origin.to_float2(),
+ size: sprite.size.to_float2(),
+ atlas_origin: sprite.atlas_origin.to_float2(),
+ color: icon.color.to_uchar4(),
+ compute_winding: 0,
+ });
+ }
+
command_encoder.set_render_pipeline_state(&self.sprite_pipeline_state);
command_encoder.set_vertex_buffer(
shaders::GPUISpriteVertexInputIndex_GPUISpriteVertexInputIndexVertices as u64,
@@ -27,12 +27,27 @@ pub struct GlyphSprite {
pub size: Vector2I,
}
+#[derive(Hash, Eq, PartialEq)]
+struct IconDescriptor {
+ path: String,
+ width: i32,
+ height: i32,
+}
+
+#[derive(Clone)]
+pub struct IconSprite {
+ pub atlas_id: usize,
+ pub atlas_origin: Vector2I,
+ pub size: Vector2I,
+}
+
pub struct SpriteCache {
device: metal::Device,
atlas_size: Vector2I,
fonts: Arc<dyn platform::FontSystem>,
atlases: Vec<Atlas>,
glyphs: HashMap<GlyphDescriptor, Option<GlyphSprite>>,
+ icons: HashMap<IconDescriptor, IconSprite>,
}
impl SpriteCache {
@@ -48,6 +63,7 @@ impl SpriteCache {
fonts,
atlases,
glyphs: Default::default(),
+ icons: Default::default(),
}
}
@@ -119,6 +135,54 @@ impl SpriteCache {
.clone()
}
+ pub fn render_icon(
+ &mut self,
+ size: Vector2F,
+ path: String,
+ svg: usvg::Tree,
+ scale_factor: f32,
+ ) -> IconSprite {
+ let atlases = &mut self.atlases;
+ let atlas_size = self.atlas_size;
+ let device = &self.device;
+ let size = (size * scale_factor).round().to_i32();
+ assert!(size.x() < atlas_size.x());
+ assert!(size.y() < atlas_size.y());
+ self.icons
+ .entry(IconDescriptor {
+ path,
+ width: size.x(),
+ height: size.y(),
+ })
+ .or_insert_with(|| {
+ let mut pixmap = tiny_skia::Pixmap::new(size.x() as u32, size.y() as u32).unwrap();
+ resvg::render(&svg, usvg::FitTo::Width(size.x() as u32), pixmap.as_mut());
+ let mask = pixmap
+ .pixels()
+ .iter()
+ .map(|a| a.alpha())
+ .collect::<Vec<_>>();
+
+ let atlas_bounds = atlases
+ .last_mut()
+ .unwrap()
+ .try_insert(size, &mask)
+ .unwrap_or_else(|| {
+ let mut atlas = Atlas::new(device, atlas_size);
+ let bounds = atlas.try_insert(size, &mask).unwrap();
+ atlases.push(atlas);
+ bounds
+ });
+
+ IconSprite {
+ atlas_id: atlases.len() - 1,
+ atlas_origin: atlas_bounds.origin(),
+ size,
+ }
+ })
+ .clone()
+ }
+
pub fn atlas_texture(&self, atlas_id: usize) -> Option<&metal::TextureRef> {
self.atlases.get(atlas_id).map(|a| a.texture.as_ref())
}
@@ -10,12 +10,13 @@ pub struct Scene {
active_layer_stack: Vec<usize>,
}
-#[derive(Default, Debug)]
+#[derive(Default)]
pub struct Layer {
clip_bounds: Option<RectF>,
quads: Vec<Quad>,
shadows: Vec<Shadow>,
glyphs: Vec<Glyph>,
+ icons: Vec<Icon>,
paths: Vec<Path>,
}
@@ -44,6 +45,13 @@ pub struct Glyph {
pub color: ColorU,
}
+pub struct Icon {
+ pub bounds: RectF,
+ pub svg: usvg::Tree,
+ pub path: String,
+ pub color: ColorU,
+}
+
#[derive(Clone, Copy, Default, Debug)]
pub struct Border {
pub width: f32,
@@ -107,6 +115,10 @@ impl Scene {
self.active_layer().push_glyph(glyph)
}
+ pub fn push_icon(&mut self, icon: Icon) {
+ self.active_layer().push_icon(icon)
+ }
+
pub fn push_path(&mut self, path: Path) {
self.active_layer().push_path(path);
}
@@ -123,6 +135,7 @@ impl Layer {
quads: Vec::new(),
shadows: Vec::new(),
glyphs: Vec::new(),
+ icons: Vec::new(),
paths: Vec::new(),
}
}
@@ -155,6 +168,14 @@ impl Layer {
self.glyphs.as_slice()
}
+ pub fn push_icon(&mut self, icon: Icon) {
+ self.icons.push(icon);
+ }
+
+ pub fn icons(&self) -> &[Icon] {
+ self.icons.as_slice()
+ }
+
fn push_path(&mut self, path: Path) {
if !path.bounds.is_empty() {
self.paths.push(path);
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M3.75 1.5a.25.25 0 00-.25.25v11.5c0 .138.112.25.25.25h8.5a.25.25 0 00.25-.25V6H9.75A1.75 1.75 0 018 4.25V1.5H3.75zm5.75.56v2.19c0 .138.112.25.25.25h2.19L9.5 2.06zM2 1.75C2 .784 2.784 0 3.75 0h5.086c.464 0 .909.184 1.237.513l3.414 3.414c.329.328.513.773.513 1.237v8.086A1.75 1.75 0 0112.25 15h-8.5A1.75 1.75 0 012 13.25V1.75z"/></svg>
@@ -175,8 +175,7 @@ impl FileFinder {
LineBox::new(
settings.ui_font_family,
settings.ui_font_size,
- Empty::new().boxed(),
- // Svg::new("icons/file-16.svg".into()).boxed(),
+ Svg::new("icons/file-16.svg".into()).boxed(),
)
.boxed(),
)