1use crate::rasterizer::Rasterizer;
2
3use crate::blitter::*;
4use sw_composite::*;
5
6use crate::dash::*;
7use crate::geom::*;
8use crate::path_builder::*;
9
10pub use crate::path_builder::Winding;
11use lyon_geom::CubicBezierSegment;
12
13#[cfg(feature = "text")]
14mod fk {
15 pub use font_kit::canvas::{Canvas, Format, RasterizationOptions};
16 pub use font_kit::font::Font;
17 pub use font_kit::hinting::HintingOptions;
18 pub use pathfinder_geometry::transform2d::Transform2F;
19 pub use pathfinder_geometry::vector::{vec2f, vec2i};
20}
21
22#[cfg(feature = "png")]
23use std::fs::*;
24#[cfg(feature = "png")]
25use std::io::BufWriter;
26
27use crate::stroke::*;
28use crate::{IntRect, IntPoint, Point, Transform, Vector};
29
30use euclid::vec2;
31
32#[derive(Clone)]
33pub struct Mask {
34 pub width: i32,
35 pub height: i32,
36 pub data: Vec<u8>,
37}
38
39#[derive(Clone, Copy, PartialEq, Debug)]
41pub struct SolidSource {
42 pub r: u8,
43 pub g: u8,
44 pub b: u8,
45 pub a: u8,
46}
47
48impl SolidSource {
49 pub fn to_u32(&self) -> u32 {
50 let color = ((self.a as u32) << 24)
51 | ((self.r as u32) << 16)
52 | ((self.g as u32) << 8)
53 | ((self.b as u32) << 0);
54 color
55 }
56
57 pub fn from_unpremultiplied_argb(a: u8, r: u8, g: u8, b: u8) -> Self {
58 SolidSource {
59 a: a,
60 r: muldiv255(a as u32, r as u32) as u8,
61 g: muldiv255(a as u32, g as u32) as u8,
62 b: muldiv255(a as u32, b as u32) as u8
63 }
64 }
65}
66
67impl From<Color> for SolidSource {
68 fn from(color: Color) -> Self {
69 SolidSource::from_unpremultiplied_argb(
70 color.a(),
71 color.r(),
72 color.g(),
73 color.b(),
74 )
75 }
76}
77
78#[derive(PartialEq, Clone, Copy, Debug)]
79pub enum BlendMode {
80 Dst,
81 Src,
82 Clear,
83 SrcOver,
84 DstOver,
85 SrcIn,
86 DstIn,
87 SrcOut,
88 DstOut,
89 SrcAtop,
90 DstAtop,
91 Xor,
92 Add,
93
94 Screen,
95 Overlay,
96 Darken,
97 Lighten,
98 ColorDodge,
99 ColorBurn,
100 HardLight,
101 SoftLight,
102 Difference,
103 Exclusion,
104 Multiply,
105 Hue,
106 Saturation,
107 Color,
108 Luminosity
109}
110
111trait Blender {
112 type Output;
113 fn build<T: blend::Blend>() -> Self::Output;
114}
115
116struct BlendRow;
117
118fn blend_row<T: blend::Blend>(src: &[u32], dst: &mut [u32]) {
119 for (dst, src) in dst.iter_mut().zip(src) {
120 *dst = T::blend(*src, *dst);
121 }
122}
123
124impl Blender for BlendRow {
125 type Output = fn(&[u32], &mut [u32]);
126 fn build<T: blend::Blend>() -> Self::Output {
127 blend_row::<T>
128 }
129}
130
131struct BlendRowMask;
132
133fn blend_row_mask<T: blend::Blend>(src: &[u32], mask: &[u8], dst: &mut [u32]) {
134 for ((dst, src), mask) in dst.iter_mut().zip(src).zip(mask) {
135 *dst = lerp(
136 *dst,
137 T::blend(*src, *dst),
138 alpha_to_alpha256(*mask as u32),
139 );
140 }
141}
142
143impl Blender for BlendRowMask {
144 type Output = fn(&[u32], &[u8], &mut [u32]);
145 fn build<T: blend::Blend>() -> Self::Output {
146 blend_row_mask::<T>
147 }
148}
149
150struct BlendRowMaskClip;
151
152fn blend_row_mask_clip<T: blend::Blend>(src: &[u32], mask: &[u8], clip: &[u8], dst: &mut [u32]) {
153 for (((dst, src), mask), clip) in dst.iter_mut().zip(src).zip(mask).zip(clip) {
154 *dst = alpha_lerp(
155 *dst,
156 T::blend(*src, *dst),
157 *mask as u32,
158 *clip as u32
159 );
160 }
161}
162
163impl Blender for BlendRowMaskClip {
164 type Output = fn(&[u32], &[u8], &[u8], &mut [u32]);
165 fn build<T: blend::Blend>() -> Self::Output {
166 blend_row_mask_clip::<T>
167 }
168}
169
170fn build_blend_proc<T: Blender>(mode: BlendMode) -> T::Output {
171 use sw_composite::blend::*;
172 match mode {
173 BlendMode::Dst => T::build::<Dst>(),
174 BlendMode::Src => T::build::<Src>(),
175 BlendMode::Clear => T::build::<Clear>(),
176 BlendMode::SrcOver => T::build::<SrcOver>(),
177 BlendMode::DstOver => T::build::<DstOver>(),
178 BlendMode::SrcIn => T::build::<SrcIn>(),
179 BlendMode::DstIn => T::build::<DstIn>(),
180 BlendMode::SrcOut => T::build::<SrcOut>(),
181 BlendMode::DstOut => T::build::<DstOut>(),
182 BlendMode::SrcAtop => T::build::<SrcAtop>(),
183 BlendMode::DstAtop => T::build::<DstAtop>(),
184 BlendMode::Xor => T::build::<Xor>(),
185 BlendMode::Add => T::build::<Add>(),
186 BlendMode::Screen => T::build::<Screen>(),
187 BlendMode::Overlay => T::build::<Overlay>(),
188 BlendMode::Darken => T::build::<Darken>(),
189 BlendMode::Lighten => T::build::<Lighten>(),
190 BlendMode::ColorDodge => T::build::<ColorDodge>(),
191 BlendMode::ColorBurn => T::build::<ColorBurn>(),
192 BlendMode::HardLight => T::build::<HardLight>(),
193 BlendMode::SoftLight => T::build::<SoftLight>(),
194 BlendMode::Difference => T::build::<Difference>(),
195 BlendMode::Exclusion => T::build::<Exclusion>(),
196 BlendMode::Multiply => T::build::<Multiply>(),
197 BlendMode::Hue => T::build::<Hue>(),
198 BlendMode::Saturation => T::build::<Saturation>(),
199 BlendMode::Color => T::build::<Color>(),
200 BlendMode::Luminosity => T::build::<Luminosity>(),
201 }
202}
203
204#[derive(Copy, Clone)]
205pub enum ExtendMode {
206 Pad,
207 Repeat
208}
209
210#[derive(Copy, Clone, PartialEq)]
211pub enum FilterMode {
212 Bilinear,
213 Nearest
214}
215
216#[derive(Clone)]
227pub enum Source<'a> {
228 Solid(SolidSource),
229 Image(Image<'a>, ExtendMode, FilterMode, Transform),
230 RadialGradient(Gradient, Spread, Transform),
231 TwoCircleRadialGradient(Gradient, Spread, Point, f32, Point, f32, Transform),
232 LinearGradient(Gradient, Spread, Transform),
233 SweepGradient(Gradient, Spread, f32, f32, Transform),
234}
235
236impl From<SolidSource> for Source<'_> {
237 fn from(other: SolidSource) -> Self {
238 Source::Solid(other)
239 }
240}
241
242impl From<Color> for Source<'_> {
243 fn from(color: Color) -> Self {
244 Source::Solid(SolidSource::from(color))
245 }
246}
247
248impl<'a> Source<'a> {
249 pub fn new_linear_gradient(gradient: Gradient, start: Point, end: Point, spread: Spread) -> Source<'a> {
252 let gradient_vector = Vector::new(end.x - start.x, end.y - start.y);
253 let length = gradient_vector.length();
255 if length != 0. {
256 let gradient_vector = gradient_vector.normalize();
257
258 let sin = gradient_vector.y;
259 let cos = gradient_vector.x;
260 let mat = Transform::new(cos, -sin, sin, cos, 0., 0.);
262
263 let mat = mat.pre_translate(vec2(-start.x, -start.y));
265
266 let mat = mat.then_scale(1. / length, 1. / length);
268 Source::LinearGradient(gradient, spread, mat)
269 } else {
270 Source::LinearGradient(gradient, spread, Transform::scale(0., 0.))
272 }
273 }
274
275 pub fn new_radial_gradient(gradient: Gradient, center: Point, radius: f32, spread: Spread) -> Source<'a> {
277 let scale = Transform::scale(radius, radius);
279 let translate = Transform::translation(center.x, center.y);
281 let transform = scale.then(&translate).inverse().unwrap();
283
284 Source::RadialGradient(gradient, spread, transform)
285 }
286
287 pub fn new_two_circle_radial_gradient(gradient: Gradient, center1: Point, radius1: f32, center2: Point, radius2: f32, spread: Spread) -> Source<'a> {
289 let transform = Transform::identity();
290 Source::TwoCircleRadialGradient(gradient, spread, center1, radius1, center2, radius2, transform)
291 }
292
293 pub fn new_sweep_gradient(gradient: Gradient, center: Point, start_angle: f32, end_angle: f32, spread: Spread) -> Source<'a> {
295 let transform = Transform::translation(-center.x, -center.y);
297 Source::SweepGradient(gradient, spread, start_angle, end_angle, transform)
298 }
299}
300
301#[derive(PartialEq, Clone, Copy, Debug)]
302pub enum AntialiasMode {
303 None,
304 Gray,
305}
306
307#[derive(PartialEq, Clone, Copy, Debug)]
308pub struct DrawOptions {
309 pub blend_mode: BlendMode,
310 pub alpha: f32,
311 pub antialias: AntialiasMode,
312}
313
314impl DrawOptions {
315 pub fn new() -> Self {
316 Default::default()
317 }
318}
319
320impl Default for DrawOptions {
321 fn default() -> Self {
322 DrawOptions {
323 blend_mode: BlendMode::SrcOver,
324 alpha: 1.,
325 antialias: AntialiasMode::Gray,
326 }
327 }
328}
329
330#[derive(Clone)]
331struct Clip {
332 rect: IntRect,
333 mask: Option<Vec<u8>>,
334}
335
336#[derive(Clone)]
337struct Layer {
338 buf: Vec<u32>,
339 opacity: f32,
340 rect: IntRect,
341 blend: BlendMode,
342}
343
344fn scaled_tolerance(x: f32, trans: &Transform) -> f32 {
345 x / trans.determinant().abs().sqrt()
348}
349
350
351
352pub struct DrawTarget<Backing = Vec<u32>> {
354 width: i32,
355 height: i32,
356 rasterizer: Rasterizer,
357 current_point: Option<Point>,
358 first_point: Option<Point>,
359 buf: Backing,
360 clip_stack: Vec<Clip>,
361 layer_stack: Vec<Layer>,
362 transform: Transform,
363}
364
365impl DrawTarget {
366 pub fn new(width: i32, height: i32) -> DrawTarget {
367 DrawTarget {
368 width,
369 height,
370 current_point: None,
371 first_point: None,
372 rasterizer: Rasterizer::new(width, height),
373 buf: vec![0; (width * height) as usize],
374 clip_stack: Vec::new(),
375 layer_stack: Vec::new(),
376 transform: Transform::identity(),
377 }
378 }
379
380 pub fn from_vec(width: i32, height: i32, mut vec: Vec<u32>) -> DrawTarget{
382 vec.resize((width*height) as usize, 0);
383 DrawTarget {
384 width,
385 height,
386 current_point: None,
387 first_point: None,
388 rasterizer: Rasterizer::new(width, height),
389 buf: vec,
390 clip_stack: Vec::new(),
391 layer_stack: Vec::new(),
392 transform: Transform::identity()
393 }
394 }
395
396 pub fn into_vec(self) -> Vec<u32> {
398 self.buf
399 }
400}
401
402impl<Backing : AsRef<[u32]> + AsMut<[u32]>> DrawTarget<Backing> {
403 pub fn from_backing(width: i32, height: i32, buf : Backing) -> Self {
407 assert_eq!((width*height) as usize, buf.as_ref().len());
408 DrawTarget {
409 width,
410 height,
411 current_point: None,
412 first_point: None,
413 rasterizer: Rasterizer::new(width, height),
414 buf,
415 clip_stack: Vec::new(),
416 layer_stack: Vec::new(),
417 transform: Transform::identity()
418 }
419 }
420
421 pub fn width(&self) -> i32 {
422 self.width
423 }
424
425 pub fn height(&self) -> i32 {
426 self.height
427 }
428
429 pub fn set_transform(&mut self, transform: &Transform) {
431 self.transform = *transform;
432 }
433
434 pub fn get_transform(&self) -> &Transform {
436 &self.transform
437 }
438
439 fn move_to(&mut self, pt: Point) {
440 self.current_point = Some(pt);
441 self.first_point = Some(pt);
442 }
443
444 fn line_to(&mut self, pt: Point) {
445 if self.current_point.is_none() {
446 self.current_point = Some(pt);
447 self.first_point = Some(pt);
448 }
449 if let Some(current_point) = self.current_point {
450 self.rasterizer
451 .add_edge(current_point, pt, false, Point::new(0., 0.));
452 self.current_point = Some(pt);
453 }
454 }
455
456 fn quad_to(&mut self, cpt: Point, pt: Point) {
457 if self.current_point.is_none() {
458 self.current_point = Some(cpt);
459 self.first_point = Some(cpt);
460 }
461 if let Some(current_point) = self.current_point {
462 let curve = [current_point, cpt, pt];
463 self.current_point = Some(curve[2]);
464 self.add_quad(curve);
465 }
466 }
467
468 fn add_quad(&mut self, mut curve: [Point; 3]) {
469 let a = curve[0].y;
470 let b = curve[1].y;
471 let c = curve[2].y;
472 if is_not_monotonic(a, b, c) {
473 let mut t_value = 0.;
474 if valid_unit_divide(a - b, a - b - b + c, &mut t_value) {
475 let mut dst = [Point::new(0., 0.); 5];
476 chop_quad_at(&curve, &mut dst, t_value);
477 flatten_double_quad_extrema(&mut dst);
478 self.rasterizer.add_edge(dst[0], dst[2], true, dst[1]);
479 self.rasterizer.add_edge(dst[2], dst[4], true, dst[3]);
480 return;
481 }
482 let b = if (a - b).abs() < (b - c).abs() { a } else { c };
485 curve[1].y = b;
486 }
487 self.rasterizer.add_edge(curve[0], curve[2], true, curve[1]);
488 }
489
490 fn cubic_to(&mut self, cpt1: Point, cpt2: Point, pt: Point) {
491 if self.current_point.is_none() {
492 self.current_point = Some(cpt1);
493 self.first_point = Some(cpt1);
494 }
495 if let Some(current_point) = self.current_point {
496 let c = CubicBezierSegment {
497 from: current_point,
498 ctrl1: cpt1,
499 ctrl2: cpt2,
500 to: pt,
501 };
502 c.for_each_quadratic_bezier(0.01, &mut |q| {
503 let curve = [q.from, q.ctrl, q.to];
504 self.add_quad(curve);
505 });
506 self.current_point = Some(pt);
507 }
508 }
509
510 fn close(&mut self) {
511 if let (Some(first_point), Some(current_point)) = (self.first_point, self.current_point) {
512 self.rasterizer.add_edge(
513 current_point,
514 first_point,
515 false,
516 Point::new(0., 0.),
517 );
518 }
519 self.current_point = self.first_point;
520 }
521
522 fn apply_path(&mut self, path: &Path) {
523
524 if self.height == 0 {
526 return;
527 }
528
529 for op in &path.ops {
530 match *op {
531 PathOp::MoveTo(pt) => {
532 self.close();
533 self.move_to(self.transform.transform_point(pt));
534 },
535 PathOp::LineTo(pt) => self.line_to(self.transform.transform_point(pt)),
536 PathOp::QuadTo(cpt, pt) => self.quad_to(
537 self.transform.transform_point(cpt),
538 self.transform.transform_point(pt),
539 ),
540 PathOp::CubicTo(cpt1, cpt2, pt) => self.cubic_to(
541 self.transform.transform_point(cpt1),
542 self.transform.transform_point(cpt2),
543 self.transform.transform_point(pt),
544 ),
545 PathOp::Close => self.close(),
546 }
547 }
548 self.close();
550 }
552
553 pub fn push_clip_rect(&mut self, rect: IntRect) {
554 let clip = match self.clip_stack.last() {
556 Some(Clip {
557 rect: current_clip,
558 mask: _,
559 }) => Clip {
560 rect: current_clip.intersection_unchecked(&rect),
561 mask: None,
562 },
563 _ => Clip {
564 rect: rect,
565 mask: None,
566 },
567 };
568 self.clip_stack.push(clip);
569 }
570
571 pub fn pop_clip(&mut self) {
572 self.clip_stack.pop();
573 }
574
575 pub fn push_clip(&mut self, path: &Path) {
576 self.apply_path(path);
577
578 let mut blitter = MaskSuperBlitter::new(0, 0, self.width, self.height);
580 self.rasterizer.rasterize(&mut blitter, path.winding);
581
582 if let Some(last) = self.clip_stack.last() {
583 if let Some(last_mask) = &last.mask {
585 for i in 0..((self.width * self.height) as usize) {
586 blitter.buf[i] = muldiv255(blitter.buf[i] as u32, last_mask[i] as u32) as u8
587 }
588 }
589 }
590
591 let current_bounds = self.clip_bounds();
592 self.clip_stack.push(Clip {
594 rect: current_bounds,
595 mask: Some(blitter.buf),
596 });
597 self.rasterizer.reset();
598 }
599
600 fn clip_bounds(&self) -> IntRect {
601 self.clip_stack.last().map(|c| c.rect).unwrap_or(IntRect::new(
602 euclid::Point2D::new(0, 0),
603 euclid::Point2D::new(self.width, self.height),
604 ))
605 }
606
607 pub fn push_layer(&mut self, opacity: f32) {
610 self.push_layer_with_blend(opacity, BlendMode::SrcOver)
611 }
612
613 pub fn push_layer_with_blend(&mut self, opacity: f32, blend: BlendMode) {
616 let rect = self.clip_bounds();
617 self.layer_stack.push(Layer {
618 rect,
619 buf: vec![0; (rect.size().width * rect.size().height) as usize],
620 opacity,
621 blend
622 });
623 }
624
625 pub fn pop_layer(&mut self) {
628 let layer = self.layer_stack.pop().unwrap();
629 let opacity = (layer.opacity * 255. + 0.5) as u8;
630 let mask = vec![opacity; (self.width * self.height) as usize];
633 let size = layer.rect.size();
634 let ctm = self.transform;
635 self.transform = Transform::identity();
636 let image = Source::Image(Image {
637 width: size.width,
638 height: size.height,
639 data: &layer.buf
640 },
641 ExtendMode::Pad,
642 FilterMode::Nearest,
643 Transform::translation(-layer.rect.min.x as f32,
644 -layer.rect.min.y as f32));
645 self.composite(&image, Some(&mask), intrect(0, 0, self.width, self.height), layer.rect, layer.blend, 1.);
646 self.transform = ctm;
647 }
648
649 pub fn draw_image_with_size_at(&mut self, width: f32, height: f32, x: f32, y: f32, image: &Image, options: &DrawOptions) {
652 let source = Source::Image(*image,
653 ExtendMode::Pad,
654 FilterMode::Bilinear,
655 Transform::translation(-x, -y).then_scale(image.width as f32 / width, image.height as f32 / height));
656
657 self.fill_rect(x, y, width, height, &source, options);
658 }
659
660 pub fn draw_image_at(&mut self, x: f32, y: f32, image: &Image, options: &DrawOptions) {
662 self.draw_image_with_size_at(image.width as f32, image.height as f32, x, y, image, options);
663 }
664
665 pub fn mask(&mut self, src: &Source, x: i32, y: i32, mask: &Mask) {
667 self.composite(src, Some(&mask.data), intrect(x, y, mask.width, mask.height), intrect(x, y, mask.width, mask.height), BlendMode::SrcOver, 1.);
668 }
669
670 pub fn stroke(&mut self, path: &Path, src: &Source, style: &StrokeStyle, options: &DrawOptions) {
672 let tolerance = 0.1;
673
674 let tolerance = scaled_tolerance(tolerance, &self.transform);
681 let mut path = path.flatten(tolerance);
682
683 if !style.dash_array.is_empty() {
684 path = dash_path(&path, &style.dash_array, style.dash_offset);
685 }
686 let stroked = stroke_to_path(&path, style);
687 self.fill(&stroked, src, options);
688 }
689
690 pub fn fill_rect(&mut self, x: f32, y: f32, width: f32, height: f32, src: &Source, options: &DrawOptions) {
693 let ix = x as i32;
694 let iy = y as i32;
695 let iwidth = width as i32;
696 let iheight = height as i32;
697 let integer_rect = ix as f32 == x && iy as f32 == y &&
698 iwidth as f32 == width && iheight as f32 == height;
699
700 if self.transform == Transform::identity() && integer_rect && self.clip_stack.is_empty() {
701 let bounds = intrect(0, 0, self.width, self.height);
702 let mut irect = intrect(ix, iy, ix + iwidth, iy + iheight);
703 irect = match irect.intersection(&bounds) {
704 Some(irect) => irect,
705 _ => return,
706 };
707 self.composite(src, None, irect, irect, options.blend_mode, options.alpha);
708 } else {
709 let mut pb = PathBuilder::new();
710 pb.rect(x, y, width, height);
711 self.fill(&pb.finish(), src, options);
712 }
713 }
714
715 pub fn fill(&mut self, path: &Path, src: &Source, options: &DrawOptions) {
717 self.apply_path(path);
718 let bounds = self.rasterizer.get_bounds();
719 if bounds.size().width > 0 && bounds.size().height > 0 {
720 match options.antialias {
721 AntialiasMode::None => {
722 let mut blitter = MaskBlitter::new(bounds.min.x, bounds.min.y, bounds.size().width, bounds.size().height);
723 self.rasterizer.rasterize(&mut blitter, path.winding);
724 self.composite(
725 src,
726 Some(&blitter.buf),
727 bounds,
728 bounds,
729 options.blend_mode,
730 options.alpha,
731 );
732 }
733 AntialiasMode::Gray => {
734 let mut blitter = MaskSuperBlitter::new(bounds.min.x, bounds.min.y, bounds.size().width, bounds.size().height);
735 self.rasterizer.rasterize(&mut blitter, path.winding);
736 self.composite(
737 src,
738 Some(&blitter.buf),
739 bounds,
740 bounds,
741 options.blend_mode,
742 options.alpha,
743 );
744 }
745 }
746 }
747 self.rasterizer.reset();
748 }
749
750 pub fn clear(&mut self, solid: SolidSource) {
752 let mut pb = PathBuilder::new();
753 if self.clip_stack.is_empty() {
754 let color = solid.to_u32();
755 for pixel in self.buf.as_mut() {
756 *pixel = color;
757 }
758 } else {
759 let ctm = self.transform;
760 self.transform = Transform::identity();
761 pb.rect(0., 0., self.width as f32, self.height as f32);
762 self.fill(
763 &pb.finish(),
764 &Source::Solid(solid),
765 &DrawOptions {
766 blend_mode: BlendMode::Src,
767 alpha: 1.,
768 antialias: AntialiasMode::Gray,
769 },
770 );
771 self.transform = ctm;
772 }
773 }
774
775 #[cfg(feature = "text")]
776 pub fn draw_text(
777 &mut self,
778 font: &fk::Font,
779 point_size: f32,
780 text: &str,
781 start: Point,
782 src: &Source,
783 options: &DrawOptions,
784 ) {
785 let mut start = fk::vec2f(start.x, start.y);
786 let mut ids = Vec::new();
787 let mut positions = Vec::new();
788 for c in text.chars() {
789 let id = font.glyph_for_char(c).unwrap();
790 ids.push(id);
791 positions.push(Point::new(start.x(), start.y()));
792 start += font.advance(id).unwrap() * point_size / 24. / 96.;
793 }
794 self.draw_glyphs(font, point_size, &ids, &positions, src, options);
795 }
796
797 #[cfg(feature = "text")]
798 pub fn draw_glyphs(
799 &mut self,
800 font: &fk::Font,
801 point_size: f32,
802 ids: &[u32],
803 positions: &[Point],
804 src: &Source,
805 options: &DrawOptions,
806 ) {
807 let antialias_mode = match options.antialias {
808 AntialiasMode::Gray => fk::RasterizationOptions::GrayscaleAa,
809 AntialiasMode::None => fk::RasterizationOptions::Bilevel,
810 };
811 let mut combined_bounds = euclid::Rect::zero();
812 for (id, position) in ids.iter().zip(positions.iter()) {
813 let bounds = font.raster_bounds(
814 *id,
815 point_size,
816 fk::Transform2F::row_major(self.transform.m11, self.transform.m12, self.transform.m21, self.transform.m22, 0., 0.)
817 .translate(fk::vec2f(position.x, position.y)),
818 fk::HintingOptions::None,
819 antialias_mode,
820 );
821 combined_bounds = match bounds {
822 Ok(bounds) => {
823 let origin = bounds.origin();
824 let size = bounds.size();
825 let bounds = euclid::Rect::new(IntPoint::new(origin.x(), origin.y()), euclid::Size2D::new(size.x(), size.y()));
826 combined_bounds.union(&bounds)
827 }
828 _ => panic!(),
829 }
830 }
831
832 let mut canvas = fk::Canvas::new(
835 fk::vec2i(combined_bounds.size.width, combined_bounds.size.height),
836 fk::Format::A8,
837 );
838 for (id, position) in ids.iter().zip(positions.iter()) {
839 let mut position = self.transform.transform_point(*position);
840 position.x -= combined_bounds.origin.x as f32;
841 position.y -= combined_bounds.origin.y as f32;
842 font.rasterize_glyph(
843 &mut canvas,
844 *id,
845 point_size,
846 fk::Transform2F::row_major(self.transform.m11, self.transform.m12, self.transform.m21, self.transform.m22, 0., 0.)
847 .translate(fk::vec2f(position.x, position.y)),
848 fk::HintingOptions::None,
849 antialias_mode,
850 ).unwrap();
851 }
852
853 self.composite(
854 src,
855 Some(&canvas.pixels),
856 combined_bounds.to_box2d(),
857 combined_bounds.to_box2d(),
858 options.blend_mode,
859 1.,
860 );
861 }
862}
863
864impl DrawTarget {
865 fn choose_blitter<'a, 'b, 'c>(mask: Option<&[u8]>, clip_stack: &'a Vec<Clip>, blitter_storage: &'b mut ShaderBlitterStorage<'a>, shader: &'a dyn Shader, blend: BlendMode, dest: &'a mut [u32], dest_bounds: IntRect, width: i32) -> &'b mut dyn Blitter {
866 *blitter_storage = match (mask, clip_stack.last()) {
867 (Some(_mask), Some(Clip {
868 rect: _,
869 mask: Some(clip),
870 })) => {
871 if blend == BlendMode::SrcOver {
872 let scb = ShaderClipMaskBlitter {
873 x: dest_bounds.min.x,
874 y: dest_bounds.min.y,
875 shader,
876 tmp: vec![0; width as usize],
877 dest,
878 dest_stride: dest_bounds.size().width,
879 clip,
880 clip_stride: width,
881 };
882 ShaderBlitterStorage::ShaderClipMaskBlitter(scb)
883 } else {
884 let blend_fn = build_blend_proc::<BlendRowMaskClip>(blend);
885 let scb_blend = ShaderClipBlendMaskBlitter {
886 x: dest_bounds.min.x,
887 y: dest_bounds.min.y,
888 shader,
889 tmp: vec![0; width as usize],
890 dest,
891 dest_stride: dest_bounds.size().width,
892 clip,
893 clip_stride: width,
894 blend_fn
895 };
896 ShaderBlitterStorage::ShaderClipBlendMaskBlitter(scb_blend)
897 }
898 }
899 (Some(_mask), _) => {
900 if blend == BlendMode::SrcOver {
901 let sb = ShaderMaskBlitter {
902 x: dest_bounds.min.x,
903 y: dest_bounds.min.y,
904 shader: &*shader,
905 tmp: vec![0; width as usize],
906 dest,
907 dest_stride: dest_bounds.size().width,
908 };
909 ShaderBlitterStorage::ShaderMaskBlitter(sb)
910 } else {
911 let blend_fn = build_blend_proc::<BlendRowMask>(blend);
912 let sb_blend = ShaderBlendMaskBlitter {
913 x: dest_bounds.min.x,
914 y: dest_bounds.min.y,
915 shader: &*shader,
916 tmp: vec![0; width as usize],
917 dest,
918 dest_stride: dest_bounds.size().width,
919 blend_fn,
920 };
921 ShaderBlitterStorage::ShaderBlendMaskBlitter(sb_blend)
922 }
923 }
924 (None, _) => {
925 let blend_fn = build_blend_proc::<BlendRow>(blend);
926 let sb_blend = ShaderBlendBlitter {
927 x: dest_bounds.min.x,
928 y: dest_bounds.min.y,
929 shader: &*shader,
930 tmp: vec![0; width as usize],
931 dest,
932 dest_stride: dest_bounds.size().width,
933 blend_fn,
934 };
935 ShaderBlitterStorage::ShaderBlendBlitter(sb_blend)
936 }
937 };
938
939 match blitter_storage {
940 ShaderBlitterStorage::None => unreachable!(),
941 ShaderBlitterStorage::ShaderBlendMaskBlitter(s) => s,
942 ShaderBlitterStorage::ShaderClipBlendMaskBlitter(s) => s,
943 ShaderBlitterStorage::ShaderMaskBlitter(s) => s,
944 ShaderBlitterStorage::ShaderClipMaskBlitter(s) => s,
945 ShaderBlitterStorage::ShaderBlendBlitter(s) => s,
946 }
947 }
948}
949
950impl<Backing : AsRef<[u32]> + AsMut<[u32]>> DrawTarget<Backing> {
951 fn composite(&mut self, src: &Source, mask: Option<&[u8]>, mask_rect: IntRect, mut rect: IntRect, blend: BlendMode, alpha: f32) {
954 let ti = self.transform.inverse();
955 let ti = if let Some(ti) = ti {
956 ti
957 } else {
958 return;
960 };
961
962 let clip_bounds = self.clip_bounds();
963
964 let (dest, dest_bounds) = match self.layer_stack.last_mut() {
965 Some(layer) => (&mut layer.buf[..], layer.rect),
966 None => (self.buf.as_mut(), intrect(0, 0, self.width, self.height))
967 };
968
969 rect = rect
970 .intersection_unchecked(&clip_bounds)
971 .intersection_unchecked(&dest_bounds)
972 .intersection_unchecked(&mask_rect);
973 if rect.is_empty() {
974 return;
975 }
976
977 let mut shader_storage = ShaderStorage::None;
978 let shader = choose_shader(&ti, src, alpha, &mut shader_storage);
979
980 let mut blitter_storage = ShaderBlitterStorage::None;
981 let blitter = DrawTarget::choose_blitter(mask, &self.clip_stack, &mut blitter_storage, shader, blend, dest, dest_bounds, self.width);
982
983 match mask {
984 Some(mask) => {
985 for y in rect.min.y..rect.max.y {
986 let mask_row = (y - mask_rect.min.y) * mask_rect.size().width;
987 let mask_start = (mask_row + rect.min.x - mask_rect.min.x) as usize;
988 let mask_end = (mask_row + rect.max.x - mask_rect.min.x) as usize;
989 blitter.blit_span(y, rect.min.x, rect.max.x, &mask[mask_start..mask_end]);
990 }
991 }
992 None => {
993 for y in rect.min.y..rect.max.y {
994 let empty_mask = [];
995 blitter.blit_span(y, rect.min.x, rect.max.x, &empty_mask[..]);
996 }
997 }
998 };
999 }
1000
1001 pub fn composite_surface<F: Fn(&[u32], &mut [u32]), SrcBacking: AsRef<[u32]>>(&mut self, src: &DrawTarget<SrcBacking>, src_rect: IntRect, dst: IntPoint, f: F) {
1003 let dst_rect = intrect(0, 0, self.width, self.height);
1004
1005 let src_rect = src_rect.intersection_unchecked(&intrect(0, 0, src.width, src.height));
1007
1008 let src_rect = dst_rect
1009 .intersection_unchecked(&src_rect.translate(dst.to_vector())).translate(-dst.to_vector());
1010
1011 let dst = IntPoint::new(dst.x.max(dst_rect.min.x).min(dst_rect.max.x),
1013 dst.y.max(dst_rect.min.y).min(dst_rect.max.y));
1014
1015 if src_rect.is_empty() {
1016 return;
1017 }
1018
1019 for y in src_rect.min.y..src_rect.max.y {
1020 let dst_row_start = (dst.x + (dst.y + y - src_rect.min.y) * self.width) as usize;
1021 let dst_row_end = dst_row_start + src_rect.size().width as usize;
1022 let src_row_start = (src_rect.min.x + y * src.width) as usize;
1023 let src_row_end = src_row_start + src_rect.size().width as usize;
1024 f(&src.buf.as_ref()[src_row_start..src_row_end], &mut self.buf.as_mut()[dst_row_start..dst_row_end]);
1025 }
1026 }
1027
1028 pub fn copy_surface<SrcBacking : AsRef<[u32]>>(&mut self, src: &DrawTarget<SrcBacking>, src_rect: IntRect, dst: IntPoint) {
1031 self.composite_surface(src, src_rect, dst, |src, dst| {
1032 dst.copy_from_slice(src)
1033 })
1034 }
1035
1036 pub fn blend_surface<SrcBacking : AsRef<[u32]>>(&mut self, src: &DrawTarget<SrcBacking>, src_rect: IntRect, dst: IntPoint, blend: BlendMode) {
1040 let blend_fn = build_blend_proc::<BlendRow>(blend);
1041 self.composite_surface(src, src_rect, dst, |src, dst| {
1042 blend_fn(src, dst);
1043 });
1044 }
1045
1046 pub fn blend_surface_with_alpha<SrcBacking : AsRef<[u32]>>(&mut self, src: &DrawTarget<SrcBacking>, src_rect: IntRect, dst: IntPoint, alpha: f32) {
1049 let alpha = (alpha * 255. + 0.5) as u8;
1050
1051 self.composite_surface(src, src_rect, dst, |src, dst| {
1052 over_in_row(src, dst, alpha as u32);
1053 });
1054 }
1055
1056 pub fn get_data(&self) -> &[u32] {
1058 self.buf.as_ref()
1059 }
1060
1061 pub fn get_data_mut(&mut self) -> &mut [u32] {
1064 self.buf.as_mut()
1065 }
1066
1067 pub fn get_data_u8(&self) -> &[u8] {
1070 let buf = self.buf.as_ref();
1071 let p = buf.as_ptr();
1072 let len = buf.len();
1073 unsafe { std::slice::from_raw_parts(p as *const u8, len * std::mem::size_of::<u32>()) }
1076 }
1077
1078 pub fn get_data_u8_mut(&mut self) -> &mut [u8] {
1081 let buf = self.buf.as_mut();
1082 let p = buf.as_mut_ptr();
1083 let len = buf.len();
1084 unsafe { std::slice::from_raw_parts_mut(p as *mut u8, len * std::mem::size_of::<u32>()) }
1087 }
1088
1089 pub fn into_inner(self) -> Backing {
1091 self.buf
1092 }
1093
1094 #[cfg(feature = "png")]
1096 pub fn write_png<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), png::EncodingError> {
1097 let file = File::create(path)?;
1098
1099 let w = &mut BufWriter::new(file);
1100
1101 let mut encoder = png::Encoder::new(w, self.width as u32, self.height as u32);
1102 encoder.set_color(png::ColorType::Rgba);
1103 encoder.set_depth(png::BitDepth::Eight);
1104 let mut writer = encoder.write_header()?;
1105 let buf = self.buf.as_ref();
1106 let mut output = Vec::with_capacity(buf.len() * 4);
1107
1108 for pixel in buf {
1109 let a = (pixel >> 24) & 0xffu32;
1110 let mut r = (pixel >> 16) & 0xffu32;
1111 let mut g = (pixel >> 8) & 0xffu32;
1112 let mut b = (pixel >> 0) & 0xffu32;
1113
1114 if a > 0u32 {
1115 r = r * 255u32 / a;
1116 g = g * 255u32 / a;
1117 b = b * 255u32 / a;
1118 }
1119
1120 output.push(r as u8);
1121 output.push(g as u8);
1122 output.push(b as u8);
1123 output.push(a as u8);
1124 }
1125
1126 writer.write_image_data(&output)
1127 }
1128}