Skip to content

Commit

Permalink
Make improvements to the overall API (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
LaurenzV authored Aug 30, 2024
1 parent fef83a7 commit 5de3bc9
Show file tree
Hide file tree
Showing 14 changed files with 185 additions and 183 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ siphasher = { workspace = true }
skrifa = { workspace = true }
tiny-skia = { workspace = true }
subsetter = { workspace = true }
rustybuzz = { workspace = true }
tiny-skia-path = { workspace = true }
usvg = { workspace = true }
flate2 = { workspace = true }
Expand All @@ -68,7 +69,6 @@ float-cmp = { workspace = true }
[dev-dependencies]
difference = { workspace = true }
paste = { workspace = true }
rustybuzz = { workspace = true }
sitro = { workspace = true }
cosmic-text = { workspace = true }
krilla-macros = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion src/font/colr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ impl<'a, 'b> ColorPainter for ColrCanvas<'a, 'b> {
self.canvas_builder.push_clip_path(path, rule);
}

self.canvas_builder.draw_path(&filled[0].0, fill);
self.canvas_builder.fill_path(&filled[0].0, fill);

for _ in clips {
self.canvas_builder.pop();
Expand Down
6 changes: 3 additions & 3 deletions src/object/annotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,11 @@ mod tests {
);

let mut surface = page.surface();
surface.draw_path(
surface.fill_path(
&rect_to_path(0.0, 0.0, 100.0, 100.0),
Fill::<Rgb>::default(),
);
surface.draw_path(
surface.fill_path(
&rect_to_path(100.0, 100.0, 200.0, 200.0),
Fill::<Rgb>::default(),
);
Expand All @@ -138,7 +138,7 @@ mod tests {
.into(),
);
let mut my_surface = page.surface();
my_surface.draw_path(
my_surface.fill_path(
&rect_to_path(100.0, 100.0, 200.0, 200.0),
Fill::<Rgb>::default(),
);
Expand Down
2 changes: 1 addition & 1 deletion src/object/mask.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ mod tests {
builder.push_rect(Rect::from_xywh(20.0, 20.0, 160.0, 160.0).unwrap());
let path = builder.finish().unwrap();

surface.draw_path(
surface.fill_path(
&path,
Fill {
paint: Paint::<Rgb>::Color(rgb::Color::new(255, 0, 0)),
Expand Down
2 changes: 1 addition & 1 deletion src/object/outline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ mod tests {

let mut page = db.start_page(Size::from_wh(200.0, 200.0).unwrap());
let mut surface = page.surface();
surface.draw_path(&path, Fill::<Rgb>::default());
surface.fill_path(&path, Fill::<Rgb>::default());
surface.finish();
page.finish();

Expand Down
4 changes: 2 additions & 2 deletions src/object/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ mod tests {
builder.push_rect(Rect::from_xywh(20.0, 20.0, 160.0, 160.0).unwrap());
let path = builder.finish().unwrap();

surface.draw_path(&path, Fill::<Rgb>::default());
surface.fill_path(&path, Fill::<Rgb>::default());
surface.finish();
let page = Page::new(
Size::from_wh(200.0, 200.0).unwrap(),
Expand All @@ -224,7 +224,7 @@ mod tests {
builder.push_rect(Rect::from_xywh(20.0, 20.0, 160.0, 160.0).unwrap());
let path = builder.finish().unwrap();

surface.draw_path(&path, Fill::<Rgb>::default());
surface.fill_path(&path, Fill::<Rgb>::default());
surface.finish();
let page = Page::new(
Size::from_wh(200.0, 200.0).unwrap(),
Expand Down
4 changes: 2 additions & 2 deletions src/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ pub struct SerializeSettings {
pub compress_content_streams: bool,
pub no_device_cs: bool,
pub svg_settings: SvgSettings,
pub(crate) force_type3_fonts: bool,
pub(crate) ignore_invalid_glyphs: bool,
pub force_type3_fonts: bool,
pub ignore_invalid_glyphs: bool,
}

#[cfg(test)]
Expand Down
14 changes: 7 additions & 7 deletions src/stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use skrifa::GlyphId;
use std::cell::RefCell;
use std::ops::Range;
use std::sync::Arc;
use tiny_skia_path::{FiniteF32, NormalizedF32, Path, PathSegment, Rect, Size, Transform};
use tiny_skia_path::{FiniteF32, NormalizedF32, Path, PathSegment, Point, Rect, Size, Transform};

#[derive(Debug, Hash, Eq, PartialEq, Clone)]
struct Repr {
Expand Down Expand Up @@ -218,16 +218,16 @@ impl ContentBuilder {
self.content_restore_state();
}

pub fn fill_glyph_run<'a>(
pub fn fill_glyphs<'a>(
&mut self,
x: f32,
y: f32,
start: Point,
sc: &mut SerializerContext,
fill: Fill<impl ColorSpace>,
glyphs: &[Glyph],
font: Font,
text: &str,
) {
let (x, y) = (start.x, start.y);
self.graphics_states.save_state();

// PDF viewers don't show patterns with fill/stroke opacities consistently.
Expand Down Expand Up @@ -256,16 +256,16 @@ impl ContentBuilder {
self.graphics_states.restore_state();
}

pub fn stroke_glyph_run<'a>(
pub fn stroke_glyphs<'a>(
&mut self,
x: f32,
y: f32,
start: Point,
sc: &mut SerializerContext,
stroke: Stroke<impl ColorSpace>,
glyphs: &[Glyph],
font: Font,
text: &str,
) {
let (x, y) = (start.x, start.y);
self.graphics_states.save_state();

// PDF viewers don't show patterns with fill/stroke opacities consistently.
Expand Down
190 changes: 138 additions & 52 deletions src/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ use crate::stream::{ContentBuilder, Glyph, Stream};
use crate::{Fill, FillRule, Stroke};
use fontdb::{Database, ID};
use pdf_writer::types::BlendMode;
use rustybuzz::{Direction, Feature, UnicodeBuffer};
use skrifa::GlyphId;
use std::collections::HashMap;
use tiny_skia_path::{Path, Size, Transform};
use tiny_skia_path::{Path, Point, Size, Transform};
use usvg::NormalizedF32;

pub enum PushInstruction {
Expand All @@ -31,32 +33,6 @@ pub struct Surface<'a> {
finish_fn: Box<dyn FnMut(Stream) + 'a>,
}

pub enum FillOrStroke<T>
where
T: ColorSpace,
{
Fill(Fill<T>),
Stroke(Stroke<T>),
}

impl<T> Into<FillOrStroke<T>> for Stroke<T>
where
T: ColorSpace,
{
fn into(self) -> FillOrStroke<T> {
FillOrStroke::Stroke(self)
}
}

impl<T> Into<FillOrStroke<T>> for Fill<T>
where
T: ColorSpace,
{
fn into(self) -> FillOrStroke<T> {
FillOrStroke::Fill(self)
}
}

impl<'a> Surface<'a> {
pub fn new(
sc: &'a mut SerializerContext,
Expand All @@ -76,43 +52,80 @@ impl<'a> Surface<'a> {
StreamBuilder::new(&mut self.sc)
}

pub fn draw_path<T>(&mut self, path: &Path, mode: impl Into<FillOrStroke<T>>)
pub fn fill_path<T>(&mut self, path: &Path, fill: Fill<T>)
where
T: ColorSpace,
{
match mode.into() {
FillOrStroke::Fill(fill) => {
Self::cur_builder(&mut self.root_builder, &mut self.sub_builders)
.fill_path(path, fill, self.sc);
}
FillOrStroke::Stroke(stroke) => {
Self::cur_builder(&mut self.root_builder, &mut self.sub_builders)
.stroke_path(path, stroke, self.sc);
}
}
Self::cur_builder(&mut self.root_builder, &mut self.sub_builders)
.fill_path(path, fill, self.sc);
}

pub fn draw_glyph_run<'b, T>(
pub fn stroke_path<T>(&mut self, path: &Path, stroke: Stroke<T>)
where
T: ColorSpace,
{
Self::cur_builder(&mut self.root_builder, &mut self.sub_builders)
.stroke_path(path, stroke, self.sc);
}

pub fn fill_glyphs<T>(
&mut self,
x: f32,
y: f32,
mode: impl Into<FillOrStroke<T>>,
start: Point,
fill: Fill<T>,
glyphs: &[Glyph],
font: Font,
text: &str,
) where
T: ColorSpace,
{
match mode.into() {
FillOrStroke::Fill(fill) => {
Self::cur_builder(&mut self.root_builder, &mut self.sub_builders)
.fill_glyph_run(x, y, self.sc, fill, glyphs, font, text);
}
FillOrStroke::Stroke(stroke) => {
Self::cur_builder(&mut self.root_builder, &mut self.sub_builders)
.stroke_glyph_run(x, y, self.sc, stroke, glyphs, font, text);
}
};
Self::cur_builder(&mut self.root_builder, &mut self.sub_builders)
.fill_glyphs(start, self.sc, fill, glyphs, font, text);
}

pub fn fill_text<T>(
&mut self,
start: Point,
fill: Fill<T>,
font: Font,
font_size: f32,
features: &[Feature],
text: &str,
) where
T: ColorSpace,
{
let glyphs = naive_shape(text, font.clone(), features, font_size);

self.fill_glyphs(start, fill, &glyphs, font, text);
}

pub fn stroke_text<T>(
&mut self,
start: Point,
stroke: Stroke<T>,
font: Font,
font_size: f32,
features: &[Feature],
text: &str,
) where
T: ColorSpace,
{
let glyphs = naive_shape(text, font.clone(), features, font_size);

self.stroke_glyphs(start, stroke, &glyphs, font, text);
}

pub fn stroke_glyphs<T>(
&mut self,
start: Point,
stroke: Stroke<T>,
glyphs: &[Glyph],
font: Font,
text: &str,
) where
T: ColorSpace,
{
Self::cur_builder(&mut self.root_builder, &mut self.sub_builders)
.stroke_glyphs(start, self.sc, stroke, glyphs, font, text);
}

pub fn push_transform(&mut self, transform: &Transform) {
Expand Down Expand Up @@ -240,6 +253,79 @@ impl Drop for Surface<'_> {
}
}

fn naive_shape(text: &str, font: Font, features: &[Feature], size: f32) -> Vec<Glyph> {
let data = font.font_data();
let rb_font = rustybuzz::Face::from_slice(data.as_ref().as_ref(), font.index()).unwrap();

let mut buffer = UnicodeBuffer::new();
buffer.push_str(text);
buffer.guess_segment_properties();

let dir = buffer.direction();

let output = rustybuzz::shape(&rb_font, features, buffer);

let positions = output.glyph_positions();
let infos = output.glyph_infos();

let mut glyphs = vec![];

for i in 0..output.len() {
let pos = positions[i];
let start_info = infos[i];

let start = start_info.cluster as usize;

let end = if dir == Direction::LeftToRight {
let mut e = i.checked_add(1);
loop {
if let Some(index) = e {
if let Some(end_info) = infos.get(index) {
if end_info.cluster == start_info.cluster {
e = index.checked_add(1);
continue;
}
}
}

break;
}

e
} else {
let mut e = i.checked_sub(1);
loop {
if let Some(index) = e {
if let Some(end_info) = infos.get(index) {
if end_info.cluster == start_info.cluster {
e = index.checked_sub(1);
} else {
break;
}
}
} else {
break;
}
}

e
}
.and_then(|last| infos.get(last))
.map_or(text.len(), |info| info.cluster as usize);

glyphs.push(Glyph::new(
GlyphId::new(start_info.glyph_id),
(pos.x_advance as f32 / font.units_per_em()) * size,
(pos.x_offset as f32 / font.units_per_em()) * size,
(pos.y_offset as f32 / font.units_per_em()) * size,
start..end,
size,
));
}

glyphs
}

pub struct PageBuilder<'a> {
sc: &'a mut SerializerContext,
size: Size,
Expand Down
4 changes: 2 additions & 2 deletions src/svg/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub fn fill_path(path: &usvg::Path, surface: &mut Surface, process_context: &mut
process_context,
tiny_skia_path::Transform::identity(),
);
surface.draw_path(&path.data(), fill);
surface.fill_path(&path.data(), fill);
}
}

Expand All @@ -43,6 +43,6 @@ pub fn stroke_path(path: &usvg::Path, surface: &mut Surface, process_context: &m
process_context,
tiny_skia_path::Transform::identity(),
);
surface.draw_path(&path.data(), stroke);
surface.stroke_path(&path.data(), stroke);
}
}
Loading

0 comments on commit 5de3bc9

Please sign in to comment.