summaryrefslogtreecommitdiffstats
path: root/wgpu
diff options
context:
space:
mode:
Diffstat (limited to 'wgpu')
-rw-r--r--wgpu/Cargo.toml2
-rw-r--r--wgpu/src/geometry.rs110
-rw-r--r--wgpu/src/image/mod.rs58
-rw-r--r--wgpu/src/image/vector.rs35
-rw-r--r--wgpu/src/layer.rs43
-rw-r--r--wgpu/src/lib.rs102
-rw-r--r--wgpu/src/shader/image.wgsl12
-rw-r--r--wgpu/src/shader/quad/solid.wgsl13
-rw-r--r--wgpu/src/text.rs8
9 files changed, 243 insertions, 140 deletions
diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml
index 30545fa2..b13ecb36 100644
--- a/wgpu/Cargo.toml
+++ b/wgpu/Cargo.toml
@@ -20,7 +20,7 @@ all-features = true
[features]
geometry = ["iced_graphics/geometry", "lyon"]
image = ["iced_graphics/image"]
-svg = ["resvg/text"]
+svg = ["iced_graphics/svg", "resvg/text"]
web-colors = ["iced_graphics/web-colors"]
webgl = ["wgpu/webgl"]
diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs
index f6213e1d..8e6f77d7 100644
--- a/wgpu/src/geometry.rs
+++ b/wgpu/src/geometry.rs
@@ -1,7 +1,7 @@
//! Build and draw geometry.
use crate::core::text::LineHeight;
use crate::core::{
- Pixels, Point, Radians, Rectangle, Size, Transformation, Vector,
+ self, Pixels, Point, Radians, Rectangle, Size, Svg, Transformation, Vector,
};
use crate::graphics::cache::{self, Cached};
use crate::graphics::color;
@@ -11,7 +11,7 @@ use crate::graphics::geometry::{
};
use crate::graphics::gradient::{self, Gradient};
use crate::graphics::mesh::{self, Mesh};
-use crate::graphics::{self, Text};
+use crate::graphics::{Image, Text};
use crate::text;
use crate::triangle;
@@ -19,16 +19,22 @@ use lyon::geom::euclid;
use lyon::tessellation;
use std::borrow::Cow;
+use std::sync::Arc;
#[derive(Debug)]
pub enum Geometry {
- Live { meshes: Vec<Mesh>, text: Vec<Text> },
+ Live {
+ meshes: Vec<Mesh>,
+ images: Vec<Image>,
+ text: Vec<Text>,
+ },
Cached(Cache),
}
#[derive(Debug, Clone)]
pub struct Cache {
pub meshes: Option<triangle::Cache>,
+ pub images: Option<Arc<[Image]>>,
pub text: Option<text::Cache>,
}
@@ -45,7 +51,17 @@ impl Cached for Geometry {
previous: Option<Self::Cache>,
) -> Self::Cache {
match self {
- Self::Live { meshes, text } => {
+ Self::Live {
+ meshes,
+ images,
+ text,
+ } => {
+ let images = if images.is_empty() {
+ None
+ } else {
+ Some(Arc::from(images))
+ };
+
if let Some(mut previous) = previous {
if let Some(cache) = &mut previous.meshes {
cache.update(meshes);
@@ -59,10 +75,13 @@ impl Cached for Geometry {
previous.text = text::Cache::new(group, text);
}
+ previous.images = images;
+
previous
} else {
Cache {
meshes: triangle::Cache::new(meshes),
+ images,
text: text::Cache::new(group, text),
}
}
@@ -78,6 +97,7 @@ pub struct Frame {
clip_bounds: Rectangle,
buffers: BufferStack,
meshes: Vec<Mesh>,
+ images: Vec<Image>,
text: Vec<Text>,
transforms: Transforms,
fill_tessellator: tessellation::FillTessellator,
@@ -96,6 +116,7 @@ impl Frame {
clip_bounds: bounds,
buffers: BufferStack::new(),
meshes: Vec::new(),
+ images: Vec::new(),
text: Vec::new(),
transforms: Transforms {
previous: Vec::new(),
@@ -232,6 +253,44 @@ impl geometry::frame::Backend for Frame {
.expect("Stroke path");
}
+ fn stroke_rectangle<'a>(
+ &mut self,
+ top_left: Point,
+ size: Size,
+ stroke: impl Into<Stroke<'a>>,
+ ) {
+ let stroke = stroke.into();
+
+ let mut buffer = self
+ .buffers
+ .get_stroke(&self.transforms.current.transform_style(stroke.style));
+
+ let top_left = self
+ .transforms
+ .current
+ .0
+ .transform_point(lyon::math::Point::new(top_left.x, top_left.y));
+
+ let size =
+ self.transforms.current.0.transform_vector(
+ lyon::math::Vector::new(size.width, size.height),
+ );
+
+ let mut options = tessellation::StrokeOptions::default();
+ options.line_width = stroke.width;
+ options.start_cap = into_line_cap(stroke.line_cap);
+ options.end_cap = into_line_cap(stroke.line_cap);
+ options.line_join = into_line_join(stroke.line_join);
+
+ self.stroke_tessellator
+ .tessellate_rectangle(
+ &lyon::math::Box2D::new(top_left, top_left + size),
+ &options,
+ buffer.as_mut(),
+ )
+ .expect("Stroke rectangle");
+ }
+
fn fill_text(&mut self, text: impl Into<geometry::Text>) {
let text = text.into();
@@ -270,7 +329,7 @@ impl geometry::frame::Backend for Frame {
height: f32::INFINITY,
};
- self.text.push(graphics::Text::Cached {
+ self.text.push(Text::Cached {
content: text.content,
bounds,
color: text.color,
@@ -335,10 +394,11 @@ impl geometry::frame::Backend for Frame {
Frame::with_clip(clip_bounds)
}
- fn paste(&mut self, frame: Frame, _at: Point) {
+ fn paste(&mut self, frame: Frame) {
self.meshes
.extend(frame.buffers.into_meshes(frame.clip_bounds));
+ self.images.extend(frame.images);
self.text.extend(frame.text);
}
@@ -348,9 +408,32 @@ impl geometry::frame::Backend for Frame {
Geometry::Live {
meshes: self.meshes,
+ images: self.images,
text: self.text,
}
}
+
+ fn draw_image(&mut self, bounds: Rectangle, image: impl Into<core::Image>) {
+ let mut image = image.into();
+
+ let (bounds, external_rotation) =
+ self.transforms.current.transform_rectangle(bounds);
+
+ image.rotation += external_rotation;
+
+ self.images.push(Image::Raster(image, bounds));
+ }
+
+ fn draw_svg(&mut self, bounds: Rectangle, svg: impl Into<Svg>) {
+ let mut svg = svg.into();
+
+ let (bounds, external_rotation) =
+ self.transforms.current.transform_rectangle(bounds);
+
+ svg.rotation += external_rotation;
+
+ self.images.push(Image::Vector(svg, bounds));
+ }
}
enum Buffer {
@@ -518,6 +601,21 @@ impl Transform {
gradient
}
+
+ fn transform_rectangle(
+ &self,
+ rectangle: Rectangle,
+ ) -> (Rectangle, Radians) {
+ let top_left = self.transform_point(rectangle.position());
+ let top_right = self.transform_point(
+ rectangle.position() + Vector::new(rectangle.width, 0.0),
+ );
+ let bottom_left = self.transform_point(
+ rectangle.position() + Vector::new(0.0, rectangle.height),
+ );
+
+ Rectangle::with_vertices(top_left, top_right, bottom_left)
+ }
}
struct GradientVertex2DBuilder {
gradient: gradient::Packed,
diff --git a/wgpu/src/image/mod.rs b/wgpu/src/image/mod.rs
index daa2fe16..1b16022a 100644
--- a/wgpu/src/image/mod.rs
+++ b/wgpu/src/image/mod.rs
@@ -149,6 +149,8 @@ impl Pipeline {
6 => Float32x2,
// Layer
7 => Sint32,
+ // Snap
+ 8 => Uint32,
),
}],
},
@@ -212,31 +214,24 @@ impl Pipeline {
transformation: Transformation,
scale: f32,
) {
- let transformation = transformation * Transformation::scale(scale);
-
let nearest_instances: &mut Vec<Instance> = &mut Vec::new();
let linear_instances: &mut Vec<Instance> = &mut Vec::new();
for image in images {
match &image {
#[cfg(feature = "image")]
- Image::Raster {
- handle,
- filter_method,
- bounds,
- rotation,
- opacity,
- } => {
+ Image::Raster(image, bounds) => {
if let Some(atlas_entry) =
- cache.upload_raster(device, encoder, handle)
+ cache.upload_raster(device, encoder, &image.handle)
{
add_instances(
[bounds.x, bounds.y],
[bounds.width, bounds.height],
- f32::from(*rotation),
- *opacity,
+ f32::from(image.rotation),
+ image.opacity,
+ image.snap,
atlas_entry,
- match filter_method {
+ match image.filter_method {
crate::core::image::FilterMethod::Nearest => {
nearest_instances
}
@@ -251,23 +246,23 @@ impl Pipeline {
Image::Raster { .. } => {}
#[cfg(feature = "svg")]
- Image::Vector {
- handle,
- color,
- bounds,
- rotation,
- opacity,
- } => {
+ Image::Vector(svg, bounds) => {
let size = [bounds.width, bounds.height];
if let Some(atlas_entry) = cache.upload_vector(
- device, encoder, handle, *color, size, scale,
+ device,
+ encoder,
+ &svg.handle,
+ svg.color,
+ size,
+ scale,
) {
add_instances(
[bounds.x, bounds.y],
size,
- f32::from(*rotation),
- *opacity,
+ f32::from(svg.rotation),
+ svg.opacity,
+ true,
atlas_entry,
nearest_instances,
);
@@ -300,6 +295,7 @@ impl Pipeline {
nearest_instances,
linear_instances,
transformation,
+ scale,
);
self.prepare_layer += 1;
@@ -375,9 +371,12 @@ impl Layer {
nearest_instances: &[Instance],
linear_instances: &[Instance],
transformation: Transformation,
+ scale_factor: f32,
) {
let uniforms = Uniforms {
transform: transformation.into(),
+ scale_factor,
+ _padding: [0.0; 3],
};
let bytes = bytemuck::bytes_of(&uniforms);
@@ -492,6 +491,7 @@ struct Instance {
_position_in_atlas: [f32; 2],
_size_in_atlas: [f32; 2],
_layer: u32,
+ _snap: u32,
}
impl Instance {
@@ -502,6 +502,10 @@ impl Instance {
#[derive(Debug, Clone, Copy, Zeroable, Pod)]
struct Uniforms {
transform: [f32; 16],
+ scale_factor: f32,
+ // Uniforms must be aligned to their largest member,
+ // this uses a mat4x4<f32> which aligns to 16, so align to that
+ _padding: [f32; 3],
}
fn add_instances(
@@ -509,6 +513,7 @@ fn add_instances(
image_size: [f32; 2],
rotation: f32,
opacity: f32,
+ snap: bool,
entry: &atlas::Entry,
instances: &mut Vec<Instance>,
) {
@@ -525,6 +530,7 @@ fn add_instances(
image_size,
rotation,
opacity,
+ snap,
allocation,
instances,
);
@@ -554,8 +560,8 @@ fn add_instances(
];
add_instance(
- position, center, size, rotation, opacity, allocation,
- instances,
+ position, center, size, rotation, opacity, snap,
+ allocation, instances,
);
}
}
@@ -569,6 +575,7 @@ fn add_instance(
size: [f32; 2],
rotation: f32,
opacity: f32,
+ snap: bool,
allocation: &atlas::Allocation,
instances: &mut Vec<Instance>,
) {
@@ -591,6 +598,7 @@ fn add_instance(
(height as f32 - 1.0) / atlas::SIZE as f32,
],
_layer: layer as u32,
+ _snap: snap as u32,
};
instances.push(instance);
diff --git a/wgpu/src/image/vector.rs b/wgpu/src/image/vector.rs
index c6d829af..74e9924d 100644
--- a/wgpu/src/image/vector.rs
+++ b/wgpu/src/image/vector.rs
@@ -1,10 +1,9 @@
use crate::core::svg;
use crate::core::{Color, Size};
-use crate::graphics::text;
use crate::image::atlas::{self, Atlas};
use resvg::tiny_skia;
-use resvg::usvg::{self, TreeTextToPath};
+use resvg::usvg;
use rustc_hash::{FxHashMap, FxHashSet};
use std::fs;
@@ -21,7 +20,7 @@ impl Svg {
pub fn viewport_dimensions(&self) -> Size<u32> {
match self {
Svg::Loaded(tree) => {
- let size = tree.size;
+ let size = tree.size();
Size::new(size.width() as u32, size.height() as u32)
}
@@ -45,38 +44,33 @@ type ColorFilter = Option<[u8; 4]>;
impl Cache {
/// Load svg
pub fn load(&mut self, handle: &svg::Handle) -> &Svg {
- use usvg::TreeParsing;
-
if self.svgs.contains_key(&handle.id()) {
return self.svgs.get(&handle.id()).unwrap();
}
- let mut svg = match handle.data() {
+ let svg = match handle.data() {
svg::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,
+ &usvg::Options::default(), // TODO: Set usvg::Options::fontdb
+ )
+ .ok()
})
.map(Svg::Loaded)
.unwrap_or(Svg::NotFound),
svg::Data::Bytes(bytes) => {
- match usvg::Tree::from_data(bytes, &usvg::Options::default()) {
+ match usvg::Tree::from_data(
+ bytes,
+ &usvg::Options::default(), // TODO: Set usvg::Options::fontdb
+ ) {
Ok(tree) => Svg::Loaded(tree),
Err(_) => Svg::NotFound,
}
}
};
- if let Svg::Loaded(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());
- }
- }
-
self.should_trim = true;
let _ = self.svgs.insert(handle.id(), svg);
@@ -127,7 +121,7 @@ impl Cache {
// It would be cool to be able to smooth resize the `svg` example.
let mut img = tiny_skia::Pixmap::new(width, height)?;
- let tree_size = tree.size.to_int_size();
+ let tree_size = tree.size().to_int_size();
let target_size = if width > height {
tree_size.scale_to_width(width)
@@ -147,8 +141,7 @@ impl Cache {
tiny_skia::Transform::default()
};
- resvg::Tree::from_usvg(tree)
- .render(transform, &mut img.as_mut());
+ resvg::render(tree, transform, &mut img.as_mut());
let mut rgba = img.take();
diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs
index 9551311d..68d5a015 100644
--- a/wgpu/src/layer.rs
+++ b/wgpu/src/layer.rs
@@ -1,5 +1,5 @@
use crate::core::{
- renderer, Background, Color, Point, Radians, Rectangle, Transformation,
+ self, renderer, Background, Color, Point, Rectangle, Svg, Transformation,
};
use crate::graphics;
use crate::graphics::color;
@@ -20,8 +20,8 @@ pub struct Layer {
pub quads: quad::Batch,
pub triangles: triangle::Batch,
pub primitives: primitive::Batch,
- pub text: text::Batch,
pub images: image::Batch,
+ pub text: text::Batch,
pending_meshes: Vec<Mesh>,
pending_text: Vec<Text>,
}
@@ -112,42 +112,35 @@ impl Layer {
self.pending_text.push(text);
}
- pub fn draw_image(
+ pub fn draw_image(&mut self, image: Image, transformation: Transformation) {
+ match image {
+ Image::Raster(image, bounds) => {
+ self.draw_raster(image, bounds, transformation);
+ }
+ Image::Vector(svg, bounds) => {
+ self.draw_svg(svg, bounds, transformation);
+ }
+ }
+ }
+
+ pub fn draw_raster(
&mut self,
- handle: crate::core::image::Handle,
- filter_method: crate::core::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: crate::core::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);
}
diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs
index ad88ce3e..d79f0dc8 100644
--- a/wgpu/src/lib.rs
+++ b/wgpu/src/lib.rs
@@ -182,19 +182,6 @@ impl Renderer {
}
}
- if !layer.text.is_empty() {
- engine.text_pipeline.prepare(
- device,
- queue,
- &self.text_viewport,
- encoder,
- &mut self.text_storage,
- &layer.text,
- layer.bounds,
- Transformation::scale(scale_factor),
- );
- }
-
#[cfg(any(feature = "svg", feature = "image"))]
if !layer.images.is_empty() {
engine.image_pipeline.prepare(
@@ -207,6 +194,19 @@ impl Renderer {
scale_factor,
);
}
+
+ if !layer.text.is_empty() {
+ engine.text_pipeline.prepare(
+ device,
+ queue,
+ &self.text_viewport,
+ encoder,
+ &mut self.text_storage,
+ &layer.text,
+ layer.bounds,
+ Transformation::scale(scale_factor),
+ );
+ }
}
}
@@ -359,17 +359,6 @@ impl Renderer {
));
}
- if !layer.text.is_empty() {
- text_layer += engine.text_pipeline.render(
- &self.text_viewport,
- &self.text_storage,
- text_layer,
- &layer.text,
- scissor_rect,
- &mut render_pass,
- );
- }
-
#[cfg(any(feature = "svg", feature = "image"))]
if !layer.images.is_empty() {
engine.image_pipeline.render(
@@ -381,6 +370,17 @@ impl Renderer {
image_layer += 1;
}
+
+ if !layer.text.is_empty() {
+ text_layer += engine.text_pipeline.render(
+ &self.text_viewport,
+ &self.text_storage,
+ text_layer,
+ &layer.text,
+ scissor_rect,
+ &mut render_pass,
+ );
+ }
}
let _ = ManuallyDrop::into_inner(render_pass);
@@ -408,6 +408,7 @@ impl Renderer {
horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Top,
shaping: core::text::Shaping::Basic,
+ wrapping: core::text::Wrapping::Word,
};
renderer.fill_text(
@@ -527,23 +528,9 @@ impl core::image::Renderer for Renderer {
self.image_cache.borrow_mut().measure_image(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);
}
}
@@ -553,23 +540,9 @@ impl core::svg::Renderer for Renderer {
self.image_cache.borrow_mut().measure_svg(handle)
}
- fn draw_svg(
- &mut self,
- handle: core::svg::Handle,
- color_filter: 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_filter,
- bounds,
- transformation,
- rotation,
- opacity,
- );
+ layer.draw_svg(svg, bounds, transformation);
}
}
@@ -593,8 +566,17 @@ impl graphics::geometry::Renderer for Renderer {
let (layer, transformation) = self.layers.current_mut();
match geometry {
- Geometry::Live { meshes, text } => {
+ Geometry::Live {
+ meshes,
+ images,
+ text,
+ } => {
layer.draw_mesh_group(meshes, transformation);
+
+ for image in images {
+ layer.draw_image(image, transformation);
+ }
+
layer.draw_text_group(text, transformation);
}
Geometry::Cached(cache) => {
@@ -602,6 +584,12 @@ impl graphics::geometry::Renderer for Renderer {
layer.draw_mesh_cache(meshes, transformation);
}
+ if let Some(images) = cache.images {
+ for image in images.iter().cloned() {
+ layer.draw_image(image, transformation);
+ }
+ }
+
if let Some(text) = cache.text {
layer.draw_text_cache(text, transformation);
}
diff --git a/wgpu/src/shader/image.wgsl b/wgpu/src/shader/image.wgsl
index 0eeb100f..bc922838 100644
--- a/wgpu/src/shader/image.wgsl
+++ b/wgpu/src/shader/image.wgsl
@@ -1,5 +1,6 @@
struct Globals {
transform: mat4x4<f32>,
+ scale_factor: f32,
}
@group(0) @binding(0) var<uniform> globals: Globals;
@@ -16,6 +17,7 @@ struct VertexInput {
@location(5) atlas_pos: vec2<f32>,
@location(6) atlas_scale: vec2<f32>,
@location(7) layer: i32,
+ @location(8) snap: u32,
}
struct VertexOutput {
@@ -38,7 +40,7 @@ fn vs_main(input: VertexInput) -> VertexOutput {
out.opacity = input.opacity;
// Calculate the vertex position and move the center to the origin
- v_pos = round(input.pos) + v_pos * input.scale - input.center;
+ v_pos = input.pos + v_pos * input.scale - input.center;
// Apply the rotation around the center of the image
let cos_rot = cos(input.rotation);
@@ -51,7 +53,13 @@ fn vs_main(input: VertexInput) -> VertexOutput {
);
// Calculate the final position of the vertex
- out.position = globals.transform * (vec4<f32>(input.center, 0.0, 0.0) + rotate * vec4<f32>(v_pos, 0.0, 1.0));
+ out.position = vec4(vec2(globals.scale_factor), 1.0, 1.0) * (vec4<f32>(input.center, 0.0, 0.0) + rotate * vec4<f32>(v_pos, 0.0, 1.0));
+
+ if bool(input.snap) {
+ out.position = round(out.position);
+ }
+
+ out.position = globals.transform * out.position;
return out;
}
diff --git a/wgpu/src/shader/quad/solid.wgsl b/wgpu/src/shader/quad/solid.wgsl
index d908afbc..8eee16bb 100644
--- a/wgpu/src/shader/quad/solid.wgsl
+++ b/wgpu/src/shader/quad/solid.wgsl
@@ -30,6 +30,15 @@ fn solid_vs_main(input: SolidVertexInput) -> SolidVertexOutput {
var pos: vec2<f32> = (input.pos + min(input.shadow_offset, vec2<f32>(0.0, 0.0)) - input.shadow_blur_radius) * globals.scale;
var scale: vec2<f32> = (input.scale + vec2<f32>(abs(input.shadow_offset.x), abs(input.shadow_offset.y)) + input.shadow_blur_radius * 2.0) * globals.scale;
+ var snap: vec2<f32> = vec2<f32>(0.0, 0.0);
+
+ if input.scale.x == 1.0 {
+ snap.x = round(pos.x) - pos.x;
+ }
+
+ if input.scale.y == 1.0 {
+ snap.y = round(pos.y) - pos.y;
+ }
var min_border_radius = min(input.scale.x, input.scale.y) * 0.5;
var border_radius: vec4<f32> = vec4<f32>(
@@ -43,13 +52,13 @@ fn solid_vs_main(input: SolidVertexInput) -> SolidVertexOutput {
vec4<f32>(scale.x + 1.0, 0.0, 0.0, 0.0),
vec4<f32>(0.0, scale.y + 1.0, 0.0, 0.0),
vec4<f32>(0.0, 0.0, 1.0, 0.0),
- vec4<f32>(pos - vec2<f32>(0.5, 0.5), 0.0, 1.0)
+ vec4<f32>(pos - vec2<f32>(0.5, 0.5) + snap, 0.0, 1.0)
);
out.position = globals.transform * transform * vec4<f32>(vertex_position(input.vertex_index), 0.0, 1.0);
out.color = input.color;
out.border_color = input.border_color;
- out.pos = input.pos * globals.scale;
+ out.pos = input.pos * globals.scale + snap;
out.scale = input.scale * globals.scale;
out.border_radius = border_radius * globals.scale;
out.border_width = input.border_width * globals.scale;
diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs
index 05db5f80..bf7eae18 100644
--- a/wgpu/src/text.rs
+++ b/wgpu/src/text.rs
@@ -585,7 +585,13 @@ fn prepare(
(
buffer.as_ref(),
- Rectangle::new(raw.position, Size::new(width, height)),
+ Rectangle::new(
+ raw.position,
+ Size::new(
+ width.unwrap_or(layer_bounds.width),
+ height.unwrap_or(layer_bounds.height),
+ ),
+ ),
alignment::Horizontal::Left,
alignment::Vertical::Top,
raw.color,