diff --git a/Cargo.lock b/Cargo.lock index adbe8301e..593836122 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -673,6 +673,14 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fount" +version = "0.1.0" +source = "git+https://github.com/dfrg/fount#8f9259ef6b634c434f3dd9472f5200565e5dcd81" +dependencies = [ + "swash", +] + [[package]] name = "futures-core" version = "0.3.21" @@ -1080,6 +1088,7 @@ dependencies = [ "image", "instant", "lyon", + "parley", "pollster", "resource", "swash", @@ -1734,6 +1743,14 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "parley" +version = "0.1.0" +dependencies = [ + "fount", + "swash", +] + [[package]] name = "percent-encoding" version = "2.1.0" diff --git a/helix-ui/Cargo.toml b/helix-ui/Cargo.toml index 3bdcfb421..ae60e5751 100644 --- a/helix-ui/Cargo.toml +++ b/helix-ui/Cargo.toml @@ -19,6 +19,7 @@ instant = "0.1.12" # swash = "0.1.4" swash = { git = "https://github.com/dfrg/swash" } # parley = { git = "https://github.com/dfrg/parley" } +parley = { path = "../../parley" } lyon = "0.17.10" diff --git a/helix-ui/src/main.rs b/helix-ui/src/main.rs index 41d3330a1..d4c2d0b74 100644 --- a/helix-ui/src/main.rs +++ b/helix-ui/src/main.rs @@ -1,3 +1,8 @@ +use parley::{ + layout::Alignment, + style::{FontFamily, FontStack, StyleProperty}, + FontContext, LayoutContext, +}; use std::borrow::Cow; use winit::{ event::{Event, WindowEvent}, @@ -97,7 +102,8 @@ impl Font { } fn font() -> VertexBuffers { - let font = Font::from_file("assets/fonts/Inter Variable/Inter.ttf", 0).unwrap(); + // let font = Font::from_file("assets/fonts/Inter Variable/Inter.ttf", 0).unwrap(); + let font = Font::from_file("assets/fonts/ttf/FiraCode-Regular.ttf", 0).unwrap(); let font = font.as_ref(); // -- Shaping @@ -106,8 +112,8 @@ fn font() -> VertexBuffers { let mut shaper = context .builder(font) .script(Script::Latin) - .size(14.) - .variations(&[("wght", 520.5)]) + .size(12.) + .variations(&[("wght", 400.0)]) .build(); shaper.add_str("a quick brown fox?"); @@ -146,23 +152,74 @@ fn font() -> VertexBuffers { .builder(font) .hint(true) .size(12.) - .variations(&[("wght", 520.5)]) + .variations(&[("wght", 400.0)]) .build(); - let glyph_id = font.charmap().map('Q'); + let glyph_id = font.charmap().map('H'); let outline = scaler.scale_outline(glyph_id).unwrap(); - // -- Tesselation + // -- Layout - // let mut encoder = Path::builder().transformed(Transform::new( - // 0.01, 0., // - // 0., 0.01, // - // 0., 0., - // )); + let mut font_ctx = FontContext::new(); + let font_family = font_ctx.register_fonts(font.data.to_vec()).unwrap(); + let mut layout_ctx: LayoutContext<[u8; 4]> = LayoutContext::new(); + // Encode glyphs into lyon paths let mut encoder = Path::builder(); + let mut encoder = encoder.transformed(Transform::default()); + + let mut builder = layout_ctx.ranged_builder(&mut font_ctx, "fn draw_edit_box_base(canvas: &mut Canvas, x: f32, y: f32, w: f32, h: f32) { ", 1.); + builder.push_default(&StyleProperty::FontStack(FontStack::Single( + FontFamily::Named(&font_family), + ))); + builder.push_default(&StyleProperty::FontSize(12.)); + builder.push_default(&StyleProperty::Brush([255, 255, 255, 255])); + // builder.push() with range to set styling + let mut layout = builder.build(); + let max_width = None; + layout.break_all_lines(max_width, Alignment::Start); + + for line in layout.lines() { + let mut last_x = 0.0; + let mut last_y = 0.0; + + for glyph_run in line.glyph_runs() { + let run = glyph_run.run(); + // let color = &glyph_run.style().brush.0; + let font = run.font(); + let font = font.as_ref(); + + let mut first = true; + + // TODO: move let scaler here + for glyph in glyph_run.positioned_glyphs() { + let delta_x = glyph.x - last_x; + let delta_y = glyph.y - last_y; + + last_x = glyph.x; + last_y = glyph.y; + + if first { + // TODO: + } + first = false; + + // TODO: each glyph will need a translate+scale along with the glyph + // or we could run the pipeline per letter? - append_outline(&mut encoder, outline.verbs(), outline.points()); + encoder.set_transform(Transform::new( + 1.0, 0.0, // + 0.0, -1.0, // invert y axis + glyph.x, glyph.y, + )); + if let Some(outline) = scaler.scale_outline(glyph.id) { + append_outline(&mut encoder, outline.verbs(), outline.points()); + }; + } + } + } + + // -- Tesselation let path = encoder.build(); let mut geometry: VertexBuffers = VertexBuffers::new(); @@ -173,7 +230,7 @@ fn font() -> VertexBuffers { tessellator .tessellate_path( &path, - &FillOptions::default(), + &FillOptions::non_zero().with_tolerance(0.01), // defaults to 0.1, compare further &mut BuffersBuilder::new(&mut geometry, |vertex: FillVertex| Vertex { position: vertex.position().to_array(), }), @@ -181,7 +238,6 @@ fn font() -> VertexBuffers { .unwrap(); } - println!("{:?}", geometry); geometry } diff --git a/helix-ui/src/shader.wgsl b/helix-ui/src/shader.wgsl index f8d654d70..bb5296480 100644 --- a/helix-ui/src/shader.wgsl +++ b/helix-ui/src/shader.wgsl @@ -14,7 +14,10 @@ var view: View; fn vs_main([[location(0)]] input: vec2) -> [[builtin(position)]] vec4 { // TODO: scale by hidpi factor? return vec4( - input.xy / view.size.xy * 2.0 * 1.5, + + 2.0 * input.x / view.size.x - 1.0, + 1.0 - 2.0 * input.y / view.size.y, + // input.xy / view.size.xy * 2.0, 0.0, 1.0 ); }