Merge Luma launcher fork into monorepo
Move trampoline files (boot-hook, watcher, overlay) into trampoline/ subdirectory. Add upstream Luma v2.3.1 source at repo root with our additions: - Page::Ha (4th nav tab) with placeholder empty state - HA tab config schema and default entity mapping (ha-home/) - Nav keys renamed: "home" → "start", new "ha" tab between Apps and Settings - All state.rs/view.rs/main.rs/tests.rs updated for 4-tab navigation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
bc3ca0f3b9
commit
cbea5a322f
204 files changed
+25056
-65
No files matched your search
+126
@@ -0,0 +1,126 @@
|
||||
//! Lazy TTF metrics and individual outlines; never preprocess an entire font.
|
||||
use geometry::lyon_tessellation::{
|
||||
FillRule,
|
||||
math::point,
|
||||
path::{Path, path::Builder},
|
||||
};
|
||||
use luma_vector_geometry::{self as geometry, Vertex};
|
||||
use owned_ttf_parser::{AsFaceRef, GlyphId, OutlineBuilder, OwnedFace};
|
||||
|
||||
pub struct Font {
|
||||
face: OwnedFace,
|
||||
}
|
||||
|
||||
pub struct LineMetrics {
|
||||
pub ascent: f32,
|
||||
pub descent: f32,
|
||||
}
|
||||
|
||||
pub struct Metrics {
|
||||
pub advance_width: f32,
|
||||
}
|
||||
|
||||
impl Font {
|
||||
pub fn from_bytes(bytes: Vec<u8>) -> Result<Self, String> {
|
||||
OwnedFace::from_vec(bytes, 0)
|
||||
.map(|face| Self { face })
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
pub fn lookup_glyph_index(&self, character: char) -> u16 {
|
||||
self.face
|
||||
.as_face_ref()
|
||||
.glyph_index(character)
|
||||
.map_or(0, |id| id.0)
|
||||
}
|
||||
|
||||
pub fn horizontal_line_metrics(&self, size: f32) -> Option<LineMetrics> {
|
||||
let face = self.face.as_face_ref();
|
||||
let scale = size / f32::from(face.units_per_em());
|
||||
Some(LineMetrics {
|
||||
ascent: f32::from(face.ascender()) * scale,
|
||||
descent: f32::from(face.descender()) * scale,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn metrics(&self, character: char, size: f32) -> Metrics {
|
||||
let face = self.face.as_face_ref();
|
||||
let glyph = GlyphId(self.lookup_glyph_index(character));
|
||||
Metrics {
|
||||
advance_width: f32::from(face.glyph_hor_advance(glyph).unwrap_or(0)) * size
|
||||
/ f32::from(face.units_per_em()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn horizontal_kern(&self, left: char, right: char, size: f32) -> Option<f32> {
|
||||
let face = self.face.as_face_ref();
|
||||
let left = face.glyph_index(left)?;
|
||||
let right = face.glyph_index(right)?;
|
||||
for table in face.tables().kern?.subtables {
|
||||
if table.horizontal
|
||||
&& !table.has_cross_stream
|
||||
&& let Some(value) = table.glyphs_kerning(left, right)
|
||||
{
|
||||
return Some(f32::from(value) * size / f32::from(face.units_per_em()));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn geometry(&self, character: char) -> Result<Vec<Vertex>, String> {
|
||||
let face = self.face.as_face_ref();
|
||||
let mut outline = GlyphOutline {
|
||||
builder: Path::builder(),
|
||||
scale: 1. / f32::from(face.units_per_em()),
|
||||
open: false,
|
||||
};
|
||||
let glyph = GlyphId(self.lookup_glyph_index(character));
|
||||
if face.outline_glyph(glyph, &mut outline).is_none() {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
if outline.open {
|
||||
outline.builder.end(true);
|
||||
}
|
||||
// Flatten at subpixel precision for glyphs up to 256 physical px/em,
|
||||
// covering the current 1080p and 4K typography with the same geometry.
|
||||
geometry::tessellate(&outline.builder.build(), 0.15 / 256., FillRule::NonZero)
|
||||
}
|
||||
}
|
||||
|
||||
struct GlyphOutline {
|
||||
builder: Builder,
|
||||
scale: f32,
|
||||
open: bool,
|
||||
}
|
||||
|
||||
impl OutlineBuilder for GlyphOutline {
|
||||
fn move_to(&mut self, x: f32, y: f32) {
|
||||
if self.open {
|
||||
self.builder.end(true);
|
||||
}
|
||||
self.builder.begin(point(x * self.scale, -y * self.scale));
|
||||
self.open = true;
|
||||
}
|
||||
fn line_to(&mut self, x: f32, y: f32) {
|
||||
self.builder.line_to(point(x * self.scale, -y * self.scale));
|
||||
}
|
||||
fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32) {
|
||||
self.builder.quadratic_bezier_to(
|
||||
point(x1 * self.scale, -y1 * self.scale),
|
||||
point(x * self.scale, -y * self.scale),
|
||||
);
|
||||
}
|
||||
fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) {
|
||||
self.builder.cubic_bezier_to(
|
||||
point(x1 * self.scale, -y1 * self.scale),
|
||||
point(x2 * self.scale, -y2 * self.scale),
|
||||
point(x * self.scale, -y * self.scale),
|
||||
);
|
||||
}
|
||||
fn close(&mut self) {
|
||||
if self.open {
|
||||
self.builder.end(true);
|
||||
self.open = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user