Implement SVG rendering

This commit is contained in:
Antonio Scandurra 2021-04-06 13:44:38 +02:00
parent 2970e934da
commit e0c43dac25
9 changed files with 505 additions and 49 deletions

314
Cargo.lock generated
View File

@ -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"

View File

@ -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"

View File

@ -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)
}
}
}

View File

@ -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();
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();
// 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
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),
)
}

View File

@ -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,

View File

@ -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())
}

View File

@ -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);

View File

@ -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>

After

Width:  |  Height:  |  Size: 445 B

View File

@ -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(),
)