mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-27 12:07:02 -06:00
Merge Shapes: a text box merges as its letters; a picture keeps its place (#653)
This commit is contained in:
@@ -49,7 +49,7 @@ pub use extent::{Region, TILE, layout_extent, pasteboard_region, slide_extent};
|
||||
pub use images::{decode as decode_image, gif_frame};
|
||||
pub use morph_path::PathMorph;
|
||||
pub use morph_text::TextMorph;
|
||||
pub use placed::{Placed, PlacedLink, PlacedText, place_slide};
|
||||
pub use placed::{Placed, PlacedLink, PlacedText, place_slide, text_outline};
|
||||
pub use table::row_heights as table_row_heights;
|
||||
pub use transition::{SlideParts, composite_transition, render_transition};
|
||||
|
||||
@@ -1850,7 +1850,7 @@ thread_local! {
|
||||
static GLYPH_CACHE: std::cell::RefCell<HashMap<(u32, u32), Arc<BezPath>>> = std::cell::RefCell::new(HashMap::new());
|
||||
}
|
||||
|
||||
fn glyph(face: &deckcraft_fonts::FontFace, gid: u32) -> Arc<BezPath> {
|
||||
pub(crate) fn glyph(face: &deckcraft_fonts::FontFace, gid: u32) -> Arc<BezPath> {
|
||||
let key = (face.id(), gid);
|
||||
if let Some(p) = GLYPH_CACHE.with(|c| c.borrow().get(&key).cloned()) {
|
||||
return p;
|
||||
|
||||
@@ -123,3 +123,32 @@ fn run_link(body: &TextBody, para: usize, at: usize) -> Option<Hyperlink> {
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// The outlines of shape `s`'s text as drawn, in the space `m` maps shape-local points to, and
|
||||
/// the colour of its first visible run: what Merge Shapes turns letters into. Empty when the
|
||||
/// shape has no text.
|
||||
pub fn text_outline(rctx: &Ctx, s: &Shape, m: Affine) -> (kurbo::BezPath, Option<deckcraft_color::Rgba>) {
|
||||
let mut out = kurbo::BezPath::new();
|
||||
let Some(body) = s.text.as_ref().filter(|b| !b.is_empty()) else { return (out, None) };
|
||||
let x = resolve::xfrm(rctx, s);
|
||||
let tr = shape_geometry(s, x.w, x.h).text_rect;
|
||||
let layout = deckcraft_text::layout(rctx, s, body, &Opts { rect: tr, fields: &deckcraft_text::NoFields, prompt_color: None, no_shrink: false });
|
||||
let m = crate::text_transform(m, tr, layout.rotation);
|
||||
let mut first = None;
|
||||
for run in &layout.runs {
|
||||
let k = run.size / run.face.upem.max(1.0);
|
||||
let skew = if run.fake_italic { Affine::new([1.0, 0.0, -0.2, 1.0, 0.0, 0.0]) } else { Affine::IDENTITY };
|
||||
for (gid, gx, gy) in &run.glyphs {
|
||||
let path = crate::glyph(&run.face, *gid);
|
||||
if path.elements().is_empty() {
|
||||
continue;
|
||||
}
|
||||
if first.is_none() && run.color.a > 0 {
|
||||
first = Some(run.color);
|
||||
}
|
||||
let at = m * crate::glyph_place(run, *gid, *gx, *gy) * skew * Affine::scale(k);
|
||||
out.extend(path.elements().iter().map(|e| at * *e));
|
||||
}
|
||||
}
|
||||
(out, first)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user