Skip to content

Commit 5de3bc9

Browse files
authored
Make improvements to the overall API (#28)
1 parent fef83a7 commit 5de3bc9

File tree

14 files changed

+185
-183
lines changed

14 files changed

+185
-183
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ siphasher = { workspace = true }
5858
skrifa = { workspace = true }
5959
tiny-skia = { workspace = true }
6060
subsetter = { workspace = true }
61+
rustybuzz = { workspace = true }
6162
tiny-skia-path = { workspace = true }
6263
usvg = { workspace = true }
6364
flate2 = { workspace = true }
@@ -68,7 +69,6 @@ float-cmp = { workspace = true }
6869
[dev-dependencies]
6970
difference = { workspace = true }
7071
paste = { workspace = true }
71-
rustybuzz = { workspace = true }
7272
sitro = { workspace = true }
7373
cosmic-text = { workspace = true }
7474
krilla-macros = { workspace = true }

src/font/colr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ impl<'a, 'b> ColorPainter for ColrCanvas<'a, 'b> {
387387
self.canvas_builder.push_clip_path(path, rule);
388388
}
389389

390-
self.canvas_builder.draw_path(&filled[0].0, fill);
390+
self.canvas_builder.fill_path(&filled[0].0, fill);
391391

392392
for _ in clips {
393393
self.canvas_builder.pop();

src/object/annotation.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,11 +116,11 @@ mod tests {
116116
);
117117

118118
let mut surface = page.surface();
119-
surface.draw_path(
119+
surface.fill_path(
120120
&rect_to_path(0.0, 0.0, 100.0, 100.0),
121121
Fill::<Rgb>::default(),
122122
);
123-
surface.draw_path(
123+
surface.fill_path(
124124
&rect_to_path(100.0, 100.0, 200.0, 200.0),
125125
Fill::<Rgb>::default(),
126126
);
@@ -138,7 +138,7 @@ mod tests {
138138
.into(),
139139
);
140140
let mut my_surface = page.surface();
141-
my_surface.draw_path(
141+
my_surface.fill_path(
142142
&rect_to_path(100.0, 100.0, 200.0, 200.0),
143143
Fill::<Rgb>::default(),
144144
);

src/object/mask.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ mod tests {
139139
builder.push_rect(Rect::from_xywh(20.0, 20.0, 160.0, 160.0).unwrap());
140140
let path = builder.finish().unwrap();
141141

142-
surface.draw_path(
142+
surface.fill_path(
143143
&path,
144144
Fill {
145145
paint: Paint::<Rgb>::Color(rgb::Color::new(255, 0, 0)),

src/object/outline.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ mod tests {
177177

178178
let mut page = db.start_page(Size::from_wh(200.0, 200.0).unwrap());
179179
let mut surface = page.surface();
180-
surface.draw_path(&path, Fill::<Rgb>::default());
180+
surface.fill_path(&path, Fill::<Rgb>::default());
181181
surface.finish();
182182
page.finish();
183183

src/object/page.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ mod tests {
204204
builder.push_rect(Rect::from_xywh(20.0, 20.0, 160.0, 160.0).unwrap());
205205
let path = builder.finish().unwrap();
206206

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

227-
surface.draw_path(&path, Fill::<Rgb>::default());
227+
surface.fill_path(&path, Fill::<Rgb>::default());
228228
surface.finish();
229229
let page = Page::new(
230230
Size::from_wh(200.0, 200.0).unwrap(),

src/serialize.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ pub struct SerializeSettings {
4848
pub compress_content_streams: bool,
4949
pub no_device_cs: bool,
5050
pub svg_settings: SvgSettings,
51-
pub(crate) force_type3_fonts: bool,
52-
pub(crate) ignore_invalid_glyphs: bool,
51+
pub force_type3_fonts: bool,
52+
pub ignore_invalid_glyphs: bool,
5353
}
5454

5555
#[cfg(test)]

src/stream.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use skrifa::GlyphId;
2828
use std::cell::RefCell;
2929
use std::ops::Range;
3030
use std::sync::Arc;
31-
use tiny_skia_path::{FiniteF32, NormalizedF32, Path, PathSegment, Rect, Size, Transform};
31+
use tiny_skia_path::{FiniteF32, NormalizedF32, Path, PathSegment, Point, Rect, Size, Transform};
3232

3333
#[derive(Debug, Hash, Eq, PartialEq, Clone)]
3434
struct Repr {
@@ -218,16 +218,16 @@ impl ContentBuilder {
218218
self.content_restore_state();
219219
}
220220

221-
pub fn fill_glyph_run<'a>(
221+
pub fn fill_glyphs<'a>(
222222
&mut self,
223-
x: f32,
224-
y: f32,
223+
start: Point,
225224
sc: &mut SerializerContext,
226225
fill: Fill<impl ColorSpace>,
227226
glyphs: &[Glyph],
228227
font: Font,
229228
text: &str,
230229
) {
230+
let (x, y) = (start.x, start.y);
231231
self.graphics_states.save_state();
232232

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

259-
pub fn stroke_glyph_run<'a>(
259+
pub fn stroke_glyphs<'a>(
260260
&mut self,
261-
x: f32,
262-
y: f32,
261+
start: Point,
263262
sc: &mut SerializerContext,
264263
stroke: Stroke<impl ColorSpace>,
265264
glyphs: &[Glyph],
266265
font: Font,
267266
text: &str,
268267
) {
268+
let (x, y) = (start.x, start.y);
269269
self.graphics_states.save_state();
270270

271271
// PDF viewers don't show patterns with fill/stroke opacities consistently.

src/surface.rs

Lines changed: 138 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ use crate::stream::{ContentBuilder, Glyph, Stream};
1010
use crate::{Fill, FillRule, Stroke};
1111
use fontdb::{Database, ID};
1212
use pdf_writer::types::BlendMode;
13+
use rustybuzz::{Direction, Feature, UnicodeBuffer};
14+
use skrifa::GlyphId;
1315
use std::collections::HashMap;
14-
use tiny_skia_path::{Path, Size, Transform};
16+
use tiny_skia_path::{Path, Point, Size, Transform};
1517
use usvg::NormalizedF32;
1618

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

34-
pub enum FillOrStroke<T>
35-
where
36-
T: ColorSpace,
37-
{
38-
Fill(Fill<T>),
39-
Stroke(Stroke<T>),
40-
}
41-
42-
impl<T> Into<FillOrStroke<T>> for Stroke<T>
43-
where
44-
T: ColorSpace,
45-
{
46-
fn into(self) -> FillOrStroke<T> {
47-
FillOrStroke::Stroke(self)
48-
}
49-
}
50-
51-
impl<T> Into<FillOrStroke<T>> for Fill<T>
52-
where
53-
T: ColorSpace,
54-
{
55-
fn into(self) -> FillOrStroke<T> {
56-
FillOrStroke::Fill(self)
57-
}
58-
}
59-
6036
impl<'a> Surface<'a> {
6137
pub fn new(
6238
sc: &'a mut SerializerContext,
@@ -76,43 +52,80 @@ impl<'a> Surface<'a> {
7652
StreamBuilder::new(&mut self.sc)
7753
}
7854

79-
pub fn draw_path<T>(&mut self, path: &Path, mode: impl Into<FillOrStroke<T>>)
55+
pub fn fill_path<T>(&mut self, path: &Path, fill: Fill<T>)
8056
where
8157
T: ColorSpace,
8258
{
83-
match mode.into() {
84-
FillOrStroke::Fill(fill) => {
85-
Self::cur_builder(&mut self.root_builder, &mut self.sub_builders)
86-
.fill_path(path, fill, self.sc);
87-
}
88-
FillOrStroke::Stroke(stroke) => {
89-
Self::cur_builder(&mut self.root_builder, &mut self.sub_builders)
90-
.stroke_path(path, stroke, self.sc);
91-
}
92-
}
59+
Self::cur_builder(&mut self.root_builder, &mut self.sub_builders)
60+
.fill_path(path, fill, self.sc);
9361
}
9462

95-
pub fn draw_glyph_run<'b, T>(
63+
pub fn stroke_path<T>(&mut self, path: &Path, stroke: Stroke<T>)
64+
where
65+
T: ColorSpace,
66+
{
67+
Self::cur_builder(&mut self.root_builder, &mut self.sub_builders)
68+
.stroke_path(path, stroke, self.sc);
69+
}
70+
71+
pub fn fill_glyphs<T>(
9672
&mut self,
97-
x: f32,
98-
y: f32,
99-
mode: impl Into<FillOrStroke<T>>,
73+
start: Point,
74+
fill: Fill<T>,
10075
glyphs: &[Glyph],
10176
font: Font,
10277
text: &str,
10378
) where
10479
T: ColorSpace,
10580
{
106-
match mode.into() {
107-
FillOrStroke::Fill(fill) => {
108-
Self::cur_builder(&mut self.root_builder, &mut self.sub_builders)
109-
.fill_glyph_run(x, y, self.sc, fill, glyphs, font, text);
110-
}
111-
FillOrStroke::Stroke(stroke) => {
112-
Self::cur_builder(&mut self.root_builder, &mut self.sub_builders)
113-
.stroke_glyph_run(x, y, self.sc, stroke, glyphs, font, text);
114-
}
115-
};
81+
Self::cur_builder(&mut self.root_builder, &mut self.sub_builders)
82+
.fill_glyphs(start, self.sc, fill, glyphs, font, text);
83+
}
84+
85+
pub fn fill_text<T>(
86+
&mut self,
87+
start: Point,
88+
fill: Fill<T>,
89+
font: Font,
90+
font_size: f32,
91+
features: &[Feature],
92+
text: &str,
93+
) where
94+
T: ColorSpace,
95+
{
96+
let glyphs = naive_shape(text, font.clone(), features, font_size);
97+
98+
self.fill_glyphs(start, fill, &glyphs, font, text);
99+
}
100+
101+
pub fn stroke_text<T>(
102+
&mut self,
103+
start: Point,
104+
stroke: Stroke<T>,
105+
font: Font,
106+
font_size: f32,
107+
features: &[Feature],
108+
text: &str,
109+
) where
110+
T: ColorSpace,
111+
{
112+
let glyphs = naive_shape(text, font.clone(), features, font_size);
113+
114+
self.stroke_glyphs(start, stroke, &glyphs, font, text);
115+
}
116+
117+
pub fn stroke_glyphs<T>(
118+
&mut self,
119+
start: Point,
120+
stroke: Stroke<T>,
121+
glyphs: &[Glyph],
122+
font: Font,
123+
text: &str,
124+
) where
125+
T: ColorSpace,
126+
{
127+
Self::cur_builder(&mut self.root_builder, &mut self.sub_builders)
128+
.stroke_glyphs(start, self.sc, stroke, glyphs, font, text);
116129
}
117130

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

256+
fn naive_shape(text: &str, font: Font, features: &[Feature], size: f32) -> Vec<Glyph> {
257+
let data = font.font_data();
258+
let rb_font = rustybuzz::Face::from_slice(data.as_ref().as_ref(), font.index()).unwrap();
259+
260+
let mut buffer = UnicodeBuffer::new();
261+
buffer.push_str(text);
262+
buffer.guess_segment_properties();
263+
264+
let dir = buffer.direction();
265+
266+
let output = rustybuzz::shape(&rb_font, features, buffer);
267+
268+
let positions = output.glyph_positions();
269+
let infos = output.glyph_infos();
270+
271+
let mut glyphs = vec![];
272+
273+
for i in 0..output.len() {
274+
let pos = positions[i];
275+
let start_info = infos[i];
276+
277+
let start = start_info.cluster as usize;
278+
279+
let end = if dir == Direction::LeftToRight {
280+
let mut e = i.checked_add(1);
281+
loop {
282+
if let Some(index) = e {
283+
if let Some(end_info) = infos.get(index) {
284+
if end_info.cluster == start_info.cluster {
285+
e = index.checked_add(1);
286+
continue;
287+
}
288+
}
289+
}
290+
291+
break;
292+
}
293+
294+
e
295+
} else {
296+
let mut e = i.checked_sub(1);
297+
loop {
298+
if let Some(index) = e {
299+
if let Some(end_info) = infos.get(index) {
300+
if end_info.cluster == start_info.cluster {
301+
e = index.checked_sub(1);
302+
} else {
303+
break;
304+
}
305+
}
306+
} else {
307+
break;
308+
}
309+
}
310+
311+
e
312+
}
313+
.and_then(|last| infos.get(last))
314+
.map_or(text.len(), |info| info.cluster as usize);
315+
316+
glyphs.push(Glyph::new(
317+
GlyphId::new(start_info.glyph_id),
318+
(pos.x_advance as f32 / font.units_per_em()) * size,
319+
(pos.x_offset as f32 / font.units_per_em()) * size,
320+
(pos.y_offset as f32 / font.units_per_em()) * size,
321+
start..end,
322+
size,
323+
));
324+
}
325+
326+
glyphs
327+
}
328+
243329
pub struct PageBuilder<'a> {
244330
sc: &'a mut SerializerContext,
245331
size: Size,

src/svg/path.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub fn fill_path(path: &usvg::Path, surface: &mut Surface, process_context: &mut
3030
process_context,
3131
tiny_skia_path::Transform::identity(),
3232
);
33-
surface.draw_path(&path.data(), fill);
33+
surface.fill_path(&path.data(), fill);
3434
}
3535
}
3636

@@ -43,6 +43,6 @@ pub fn stroke_path(path: &usvg::Path, surface: &mut Surface, process_context: &m
4343
process_context,
4444
tiny_skia_path::Transform::identity(),
4545
);
46-
surface.draw_path(&path.data(), stroke);
46+
surface.stroke_path(&path.data(), stroke);
4747
}
4848
}

0 commit comments

Comments
 (0)