Embedder primitives: placed-child clipping, offscreen RGBA readback, standalone text measurement
Three additions an embedder needs to drive ltk as the render backend for a retained, externally-owned widget tree, each kept general rather than tied to one consumer. Stack placed-child clipping. `Stack::push_placed_clipped(e, rect, clip)` places a child at an exact rect like `push_placed` but clips its subtree's drawing to `clip` (in the Stack's coordinate space) — Android's clipChildren: content that overflows, such as a scrolled list row reaching above the list or an inner card past a rounded bubble, is not painted. The Stack child tuple grows an 8th `Option<Rect>` for the clip, and `layout_and_draw` brackets a clipped child with `set_clip_rects`/restore around the recursion. The clip is shifted by the Stack's own origin to match the placed rect (which `Stack::layout` already offsets), so a Stack laid out at a non-zero origin clips in the right place rather than off by that origin. Offscreen RGBA readback. `Canvas::read_rgba_pixels(out)` reads any canvas into tightly packed straight-alpha RGBA8, top-left row first. Unlike `read_gles_rgba_pixels` it also serves the software backend, un-premultiplying its pixmap, so an offscreen software canvas (an embedder's scratch bitmap) can be read back into a straight-alpha buffer. `Canvas::is_software()` lets a caller branch on the backend — e.g. to honour a real path clip on software but only a bounding rect on GLES. Standalone text measurement. `measure_text(text, size)`, re-exported at the crate root, measures one line with the default UI font and the system fallback chain, returning `(width, line_height)` in pixels without a live `Canvas` — for an embedder's measure pass that must produce the same metrics the renderer will later use. It is backed by `system_fonts::primary_handle()`, a process-wide cached handle for the primary UI font (the same default a canvas loads, with the bundled-font fallback), which widens `render::helpers::load_default_font_bytes` to `pub(crate)`.
This commit is contained in:
@@ -118,7 +118,7 @@ pub ( crate ) fn find_font_opt() -> Option<String>
|
||||
/// OFL 1.1) when nothing matches or the file cannot be read. Always
|
||||
/// returns usable bytes so canvas construction never panics on a
|
||||
/// system without the expected fonts.
|
||||
pub ( super ) fn load_default_font_bytes() -> Vec<u8>
|
||||
pub ( crate ) fn load_default_font_bytes() -> Vec<u8>
|
||||
{
|
||||
if let Some( path ) = find_font_opt()
|
||||
{
|
||||
|
||||
@@ -262,6 +262,45 @@ impl Canvas
|
||||
}
|
||||
}
|
||||
|
||||
/// 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.
|
||||
pub fn is_software( &self ) -> bool
|
||||
{
|
||||
matches!( self, Canvas::Software( _ ) )
|
||||
}
|
||||
|
||||
/// Read this canvas into tightly packed straight-alpha RGBA8, top-left row
|
||||
/// first (`out.len()` must be at least width*height*4). 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.
|
||||
pub fn read_rgba_pixels( &self, out: &mut [u8] ) -> Result<(), String>
|
||||
{
|
||||
match self
|
||||
{
|
||||
Canvas::Software( c ) =>
|
||||
{
|
||||
let pixels = c.pixmap.pixels();
|
||||
if out.len() < pixels.len() * 4
|
||||
{
|
||||
return Err( "read_rgba_pixels: output buffer too small".to_string() );
|
||||
}
|
||||
for ( i, p ) in pixels.iter().enumerate()
|
||||
{
|
||||
let d = p.demultiply();
|
||||
let o = i * 4;
|
||||
out[ o ] = d.red();
|
||||
out[ o + 1 ] = d.green();
|
||||
out[ o + 2 ] = d.blue();
|
||||
out[ o + 3 ] = d.alpha();
|
||||
}
|
||||
Ok( () )
|
||||
}
|
||||
Canvas::Gles( c ) => c.read_rgba_pixels( out ),
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 —
|
||||
|
||||
Reference in New Issue
Block a user