pub enum Canvas {
Software(SoftwareCanvas),
Gles(GlesCanvas),
}Expand description
Per-frame rendering surface. Wraps a backend (software or GPU) behind an enum so widgets can stay backend-agnostic.
All drawing methods are dispatched by match self — no dyn
indirection, so the backend branch stays predictable and
inlinable in the hot path.
Variants§
Software(SoftwareCanvas)
CPU rasterisation via tiny-skia, written to a
wl_shm buffer.
Gles(GlesCanvas)
GPU rasterisation via EGL + GLES 2/3. Presents via
eglSwapBuffers; Canvas::write_to_wayland_buf is a no-op
for this variant.
Implementations§
Source§impl Canvas
impl Canvas
Sourcepub fn new(width: u32, height: u32) -> Self
pub fn new(width: u32, height: u32) -> Self
Build a software canvas. The GPU backend requires an EGL
context — see Canvas::new_gles.
Sourcepub fn new_gles(
gl: Arc<Context>,
version: GlesVersion,
width: u32,
height: u32,
) -> Self
pub fn new_gles( gl: Arc<Context>, version: GlesVersion, width: u32, height: u32, ) -> Self
Build a GPU canvas on an already-current EGL context.
Sourcepub fn viewport_logical(&self) -> (f32, f32)
pub fn viewport_logical(&self) -> (f32, f32)
(width, height) of the surface in logical pixels (physical
size divided by dpi_scale). This is the right viewport for
resolving crate::Length values, which are themselves in
logical units. Falls back to physical size if dpi_scale is
0 or negative so a misconfigured canvas still returns a usable
non-zero viewport instead of NaN/inf.
let mut c = Canvas::new( 720, 1440 );
c.set_dpi_scale( 2.0 );
assert_eq!( c.viewport_logical(), ( 360.0, 720.0 ) );Sourcepub fn viewport_layout(&self) -> (f32, f32)
pub fn viewport_layout(&self) -> (f32, f32)
(width, height) of the surface in physical pixels — the same
space the layout tree is computed in (the root rect is pw × ph).
This is the viewport that layout-affecting crate::Length values
(widths, paddings, gaps, widget sizes) must resolve against so a
Vw(100) fills the surface. Text font sizes are the exception:
they resolve against Self::viewport_logical and are then scaled
by dpi_scale at raster time, so they must NOT use this.
Sourcepub fn density(&self) -> f32
pub fn density(&self) -> f32
Pixel density used to resolve crate::LengthBase::Dp values on
this canvas: the canvas-local density when one was pinned with
Self::set_density, the process crate::density otherwise.
Sourcepub fn set_density(&mut self, d: f32)
pub fn set_density(&mut self, d: f32)
Pin this canvas — and every sub-canvas later derived from it — to
a pixel density, overriding the process crate::density for
Dp resolution. For a surface sitting on an output whose DPI
differs from the one the process global was derived from.
Sourcepub fn resolve_geom(&self, l: Length) -> f32
pub fn resolve_geom(&self, l: Length) -> f32
Resolve an explicit Length in geometry space: against
Self::viewport_layout, with this canvas’ Self::density.
Widgets resolve caller-supplied geometry lengths through this so
a Length::dp override follows the canvas the widget draws on.
Sourcepub fn resolve_font(&self, l: Length) -> f32
pub fn resolve_font(&self, l: Length) -> f32
Resolve an explicit Length in font space: against
Self::viewport_logical, with this canvas’ Self::density,
times the global accessibility crate::text_scale. Counterpart
of Self::resolve_geom for font sizes, which are handed to the
raster path pre-dpi_scale, so Dp uses density / dpi_scale.
Sourcepub fn geom_px(&self, design_px: f32) -> f32
pub fn geom_px(&self, design_px: f32) -> f32
Resolve a stock-widget geometry design pixel (height, padding,
box size, gap…) through the process-wide crate::WidgetScaling
mode, into a concrete physical-pixel value for the layout tree.
Widgets call this instead of using a raw theme:: constant so their
intrinsic geometry follows the app’s chosen adaptation strategy
(crate::WidgetScaling::Fluid → surface-proportional,
crate::WidgetScaling::Physical → constant physical size). Geometry
lives in physical space, so this resolves against
Self::viewport_layout.
Sourcepub fn font_px(&self, design_px: f32) -> f32
pub fn font_px(&self, design_px: f32) -> f32
Resolve a stock-widget font design pixel through the process-wide
crate::WidgetScaling mode. Font sizes are handed to the raster
path pre-dpi_scale, so this bridges the logical/physical split for
each mode: in crate::WidgetScaling::Fluid it resolves the fluid
size against Self::viewport_logical (so × dpi_scale at raster
yields a surface-proportional physical size); in
crate::WidgetScaling::Physical it divides the density-scaled size
by dpi_scale (so × dpi_scale yields a constant physical size).
Sourcepub fn borrowed_gles_texture(&self) -> Option<BorrowedGlesTexture>
pub fn borrowed_gles_texture(&self) -> Option<BorrowedGlesTexture>
Borrow the GLES texture backing this canvas, when the canvas is GPU-backed.
Sourcepub fn read_gles_rgba_pixels(&self, out: &mut [u8]) -> Result<(), String>
pub fn read_gles_rgba_pixels(&self, out: &mut [u8]) -> Result<(), String>
Read a GLES canvas into tightly packed RGBA8, top-left row
first. Intentionally unavailable for software canvases because
the software backend’s canonical export path is
Self::write_to_wayland_buf.
Sourcepub fn is_software(&self) -> bool
pub fn is_software(&self) -> bool
Whether this is the CPU (software) backend. Callers that can honour a real path clip on the software backend but only a bounding rect on GLES branch on this.
Sourcepub fn read_rgba_pixels(&self, out: &mut [u8]) -> Result<(), String>
pub fn read_rgba_pixels(&self, out: &mut [u8]) -> Result<(), String>
Read this canvas into tightly packed straight-alpha RGBA8, top-left row
first (out.len() must be at least widthheight4). Unlike
Self::read_gles_rgba_pixels this also serves the software backend, by
un-premultiplying its pixmap — used to read back an offscreen software
canvas (e.g. an Android Canvas(Bitmap)) into a straight-alpha buffer.
Sourcepub fn draw_external_texture(
&mut self,
texture: Texture,
dest: Rect,
opacity: f32,
)
pub fn draw_external_texture( &mut self, texture: Texture, dest: Rect, opacity: f32, )
Composite an externally-owned GL texture into dest. No-op on
the software backend (no GL state to sample from). Used by
widgets that host content rendered by an external producer —
the producer keeps ownership of the texture name; this call
only samples it through the standard texture program.
pub fn dpi_scale(&self) -> f32
pub fn set_dpi_scale(&mut self, s: f32)
pub fn global_alpha(&self) -> f32
pub fn set_global_alpha(&mut self, a: f32)
Sourcepub fn set_composite_mode(&mut self, mode: CompositeMode)
pub fn set_composite_mode(&mut self, mode: CompositeMode)
How the following draws, blits included, combine with the canvas. GPU canvases only; a software canvas always composites src-over.
Sourcepub fn font(&self) -> &FontFace
pub fn font(&self) -> &FontFace
Shared font handle. Exposed so widgets that need raw face
access (e.g. Text for ascent/descent) do not have to go
through wrappers for every metric they read.
Sourcepub fn set_font_registry(&mut self, registry: Arc<FontRegistry>)
pub fn set_font_registry(&mut self, registry: Arc<FontRegistry>)
Install a theme font registry on the active backend.
Sourcepub fn font_for(
&self,
family: &str,
weight: u16,
style: FontStyle,
) -> Arc<FontFace>
pub fn font_for( &self, family: &str, weight: u16, style: FontStyle, ) -> Arc<FontFace>
Resolve a specific font via the theme registry, falling back
to the system-default Self::font when no registry is
installed or the triple cannot be satisfied.
Sourcepub fn font_metrics(&self, ch: char, size: f32) -> Metrics
pub fn font_metrics(&self, ch: char, size: f32) -> Metrics
Convenience wrapper around font().metrics(...) already
pre-scaled by dpi_scale. Most callers want this rather than
the raw font handle.
Sourcepub fn font_line_metrics(&self, size: f32) -> Option<LineMetrics>
pub fn font_line_metrics(&self, size: f32) -> Option<LineMetrics>
Convenience wrapper around font().horizontal_line_metrics(...),
pre-scaled by dpi_scale like Self::font_metrics.
pub fn resize(&mut self, width: u32, height: u32)
pub fn sub_canvas(&self, width: u32, height: u32) -> Canvas
pub fn blit(&mut self, src: &Canvas, dest_x: i32, dest_y: i32)
Sourcepub fn blit_fade_bottom(
&mut self,
src: &Canvas,
dest_x: i32,
dest_y: i32,
fade_bottom_px: f32,
)
pub fn blit_fade_bottom( &mut self, src: &Canvas, dest_x: i32, dest_y: i32, fade_bottom_px: f32, )
Like Self::blit but feathers the last fade_bottom_px source
rows so the bottom edge fades to transparent. The software backend
currently ignores fade_bottom_px, so the dissolve is GLES-only.
pub fn set_clip_rects(&mut self, rects: &[Rect])
Sourcepub fn set_clip_path(&mut self, cmds: &[PathCmd])
pub fn set_clip_path(&mut self, cmds: &[PathCmd])
Clip subsequent draws to an arbitrary vector path (in surface
coordinates). Anti-aliased per-path clipping: the software backend uses a
tiny-skia coverage mask; the GLES backend captures the clipped draws into
an offscreen layer and composites it back through an anti-aliased coverage
mask. Replaces any active clip; restore the previous clip via
Self::set_clip_rects with
a Self::clip_bounds snapshot taken beforehand, or Self::clear_clip.
Sourcepub fn clip_bounds(&self) -> Vec<Rect>
pub fn clip_bounds(&self) -> Vec<Rect>
Snapshot the currently installed clip bounds (empty when no clip
is active). Used by widgets that need to install a tighter clip
for a single primitive and then restore whatever the outer
partial-redraw or sub-canvas clip was — there is no stack
internally, so round-tripping through
Self::set_clip_rects with the snapshot is how to compose.
pub fn clear_clip(&mut self)
pub fn clear(&mut self)
pub fn fill(&mut self, color: Color)
pub fn fill_rect( &mut self, rect: Rect, color: Color, corners: impl Into<Corners>, )
Sourcepub fn fill_paint_rect(
&mut self,
rect: Rect,
paint: &ThemePaint,
corners: impl Into<Corners>,
)
pub fn fill_paint_rect( &mut self, rect: Rect, paint: &ThemePaint, corners: impl Into<Corners>, )
Paint-driven rectangle fill.
Dispatches on the crate::theme::Paint variant. Solid
fills go straight through Self::fill_rect. Gradients
(linear and radial) are routed to dedicated shaders on the
GPU backend; on the Software backend they still collapse to a
flat fill from the first stop — tiny-skia can render
gradients natively, but wiring that up is left for a
follow-up.
pub fn stroke_rect( &mut self, rect: Rect, color: Color, width: f32, corners: impl Into<Corners>, )
Sourcepub fn fill_path(&mut self, cmds: &[PathCmd], color: Color)
pub fn fill_path(&mut self, cmds: &[PathCmd], color: Color)
Fill an arbitrary vector path (commands in surface coordinates) with a solid colour. The software backend rasterises with tiny-skia directly; the GLES backend rasterises into a tiny-skia pixmap and blits it (the CPU fallback — no path shader on the GPU path).
Sourcepub fn stroke_path(&mut self, cmds: &[PathCmd], color: Color, width: f32)
pub fn stroke_path(&mut self, cmds: &[PathCmd], color: Color, width: f32)
Stroke an arbitrary vector path (commands in surface coordinates).
Sourcepub fn fill_shadow_outer(
&mut self,
target: Rect,
shadow: &Shadow,
corners: impl Into<Corners>,
)
pub fn fill_shadow_outer( &mut self, target: Rect, shadow: &Shadow, corners: impl Into<Corners>, )
Paint an outer drop shadow behind the rounded rect target.
On the GPU backend this runs an analytic soft-shadow shader in one draw call — no FBO, no cache, no readback. On the Software backend it is a no-op today.
Sourcepub fn fill_shadow_inset(
&mut self,
target: Rect,
shadow: &InsetShadow,
corners: impl Into<Corners>,
)
pub fn fill_shadow_inset( &mut self, target: Rect, shadow: &InsetShadow, corners: impl Into<Corners>, )
Paint an inner (inset) shadow inside the rounded rect
target.
On the GPU backend, uses a dedicated shader whose inner SDF
encodes shadow.offset and shadow.spread. The blend state
is switched per-call to honour shadow.blend: Normal,
PlusLighter, Multiply and Screen map to fixed-function
blend modes; Overlay routes through a dedicated shader that
snapshots the FBO and computes the CSS Overlay formula
in-shader.
On the Software backend this is a no-op today.
Sourcepub fn fill_surface(
&mut self,
rect: Rect,
fill: &ThemePaint,
outer_shadows: &[Shadow],
inset_shadows: &[InsetShadow],
corners: impl Into<Corners>,
)
pub fn fill_surface( &mut self, rect: Rect, fill: &ThemePaint, outer_shadows: &[Shadow], inset_shadows: &[InsetShadow], corners: impl Into<Corners>, )
Unified surface painter. Composes a themed surface in the canonical paint order: outer shadows → fill → insets.
pub fn draw_line( &mut self, x0: f32, y0: f32, x1: f32, y1: f32, color: Color, width: f32, )
pub fn draw_text(&mut self, text: &str, x: f32, y: f32, size: f32, color: Color)
Sourcepub fn draw_text_with_font(
&mut self,
text: &str,
x: f32,
y: f32,
size: f32,
color: Color,
font: &Arc<FontFace>,
)
pub fn draw_text_with_font( &mut self, text: &str, x: f32, y: f32, size: f32, color: Color, font: &Arc<FontFace>, )
Draw text with an explicitly supplied font instead of the
canvas default. Use Self::font_for to resolve a (family, weight, style) triple from the active theme registry first.
pub fn measure_text(&self, text: &str, size: f32) -> f32
Sourcepub fn measure_char(&self, ch: char, size: f32) -> f32
pub fn measure_char(&self, ch: char, size: f32) -> f32
The advance of ch alone, as Self::measure_text gives it, kept so that a layout measuring a long text character by character does not shape each one again.
Sourcepub fn measure_char_with_font(
&self,
ch: char,
size: f32,
font: &Arc<FontFace>,
) -> f32
pub fn measure_char_with_font( &self, ch: char, size: f32, font: &Arc<FontFace>, ) -> f32
Self::measure_char in font instead of the canvas’s.
Sourcepub fn measure_text_with_font(
&self,
text: &str,
size: f32,
font: &Arc<FontFace>,
) -> f32
pub fn measure_text_with_font( &self, text: &str, size: f32, font: &Arc<FontFace>, ) -> f32
Width of text rendered with font. Mirrors
Self::measure_text but bypasses the canvas default font so
text laid out at one weight and drawn at another stays aligned.
pub fn draw_image_data( &mut self, rgba_data: &[u8], img_w: u32, img_h: u32, dest: Rect, opacity: f32, )
Sourcepub fn draw_image_keyed(
&mut self,
key: u64,
rgba_data: &[u8],
img_w: u32,
img_h: u32,
dest: Rect,
opacity: f32,
)
pub fn draw_image_keyed( &mut self, key: u64, rgba_data: &[u8], img_w: u32, img_h: u32, dest: Rect, opacity: f32, )
Self::draw_image_data with key naming the pixels instead of a fingerprint of them, so a caller that draws the same images on every frame, such as a terminal’s glyphs, does not hash them each time. Every draw with the same key must pass the same pixels: they are read only when the image is not cached. A key never names an image drawn through draw_image_data.
Sourcepub fn clear_rects_transparent(&mut self, rects: &[Rect])
pub fn clear_rects_transparent(&mut self, rects: &[Rect])
Zero pixels inside each rect — used by the partial-redraw path when the surface background is fully transparent.
Sourcepub fn write_to_wayland_buf(&self, buf: &mut [u8], swap_rb: bool)
pub fn write_to_wayland_buf(&self, buf: &mut [u8], swap_rb: bool)
Copy / present the rendered frame. For software this fills a
wl_shm buffer (with optional R/B swap for Argb8888). For
GPU the commit happens via eglSwapBuffers elsewhere — this
call is a no-op.
Sourcepub fn present(&mut self)
pub fn present(&mut self)
Publish the in-progress GPU frame: blit the FBO onto the EGL
window’s default framebuffer. The follow-up eglSwapBuffers
(done outside the canvas) is what actually commits to the
compositor. No-op on software, where presentation is the SHM
attach_to/commit pair.
Sourcepub fn present_to(&mut self, width: u32, height: u32)
pub fn present_to(&mut self, width: u32, height: u32)
Self::present onto a window framebuffer of width × height physical pixels, the frame stretched to cover it where a fractional scale left the canvas a pixel smaller or larger.
Auto Trait Implementations§
impl Freeze for Canvas
impl !RefUnwindSafe for Canvas
impl !Send for Canvas
impl !Sync for Canvas
impl Unpin for Canvas
impl !UnwindSafe for Canvas
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more