raqote/
draw_target.rs

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/// A premultiplied color. i.e. r,b,g <= a
40#[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/// LinearGradients have an implicit start point at 0,0 and an end point at 256,0. The transform
217/// parameter can be used to adjust them to the desired location.
218/// RadialGradients have an implicit center at 0,0 and a radius of 128.
219/// The helper functions: `new_linear_gradient`, `new_radial_gradient` and `new_two_circle_radial_gradient`
220/// allow the gradients to be constructed with easier to understand inputs.
221/// The `transform` parameter maps user space to source space. This means that setting the same transform
222/// on the draw target as the source will have the effect of canceling out.
223///
224/// These locations are an artifact of the blitter implementation and will probably change in the
225/// future to become more ergonomic.
226#[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    /// Creates a new linear gradient source where the start point corresponds to the gradient
250    /// stop at position = 0 and the end point corresponds to the gradient stop at position = 1.
251    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        // Get length of desired gradient vector
254        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            // Build up a rotation matrix from our vector
261            let mat = Transform::new(cos, -sin, sin, cos, 0., 0.);
262
263            // Adjust for the start point
264            let mat = mat.pre_translate(vec2(-start.x, -start.y));
265
266            // Scale gradient to desired length
267            let mat = mat.then_scale(1. / length, 1. / length);
268            Source::LinearGradient(gradient, spread, mat)
269        } else {
270            // use some degenerate matrix
271            Source::LinearGradient(gradient, spread, Transform::scale(0., 0.))
272        }
273    }
274
275    /// Creates a new radial gradient that is centered at the given point and has the given radius.
276    pub fn new_radial_gradient(gradient: Gradient, center: Point, radius: f32, spread: Spread) -> Source<'a> {
277        // Scale gradient to desired radius
278        let scale = Transform::scale(radius, radius);
279        // Transform gradient to center of gradient
280        let translate = Transform::translation(center.x, center.y);
281        // Compute final transform
282        let transform = scale.then(&translate).inverse().unwrap();
283
284        Source::RadialGradient(gradient, spread, transform)
285    }
286
287    /// Creates a new radial gradient that is centered at the given point and has the given radius.
288    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    /// Creates a new sweep gradient that is centered at the given point with `start_angle` and `end_angle`.
294    pub fn new_sweep_gradient(gradient: Gradient, center: Point, start_angle: f32, end_angle: f32, spread: Spread) -> Source<'a> {
295        // Transform gradient to center of gradient
296        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    // The absolute value of the determinant is the area parallelogram
346    // Take the sqrt of the area to losily convert to one dimension
347    x / trans.determinant().abs().sqrt()
348}
349
350
351
352/// The main type used for drawing
353pub 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    /// Use a previously used vector for the bitmap and extend it to the given size(if needed)
381    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    /// Take ownership of the buffer backing the DrawTarget
397    pub fn into_vec(self) -> Vec<u32> {
398        self.buf
399    }
400}
401
402impl<Backing : AsRef<[u32]> + AsMut<[u32]>> DrawTarget<Backing> {
403    /// Use an existing backing storage for the bitmap
404    ///
405    /// The backing store must be the correct size (width*height elements).
406    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    /// sets a transform that will be applied to all drawing operations
430    pub fn set_transform(&mut self, transform: &Transform) {
431        self.transform = *transform;
432    }
433
434    /// gets the current transform
435    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            // if we get here, we need to force dst to be monotonic, even though
483            // we couldn't compute a unit_divide value (probably underflow).
484            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        // we have no height so there can be no edges
525        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        // make sure the path is closed
549        self.close();
550        // XXX: we'd like for this function to return the bounds of the path
551    }
552
553    pub fn push_clip_rect(&mut self, rect: IntRect) {
554        // intersect with current clip
555        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        // XXX: restrict to clipped area
579        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            // combine with previous mask
584            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        //XXX: handle interleaving of clip rect/masks better
593        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    /// Pushes a new layer as the drawing target. This is used for implementing
608    /// group opacity effects.
609    pub fn push_layer(&mut self, opacity: f32) {
610        self.push_layer_with_blend(opacity, BlendMode::SrcOver)
611    }
612
613    /// Pushes a new layer as the drawing target. This is used for implementing
614    /// group opacity or blend effects.
615    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    /// Draws the most recently pushed layer to the drawing target with
626    /// the pushed opacity applied.
627    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        // Allocating an entire mask just for the opacity is needlessly bad.
631        // We should be able to fix it once the blitters work better.
632        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    /// Draws an image at (x, y) with the size (width, height). This will rescale the image to the
650    /// destination size.
651    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    /// Draws an image at x, y
661    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    /// Draws `src` through an untransformed `mask` positioned at `x`, `y` in device space
666    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    /// Strokes `path` with `style` and fills the result with `src`
671    pub fn stroke(&mut self, path: &Path, src: &Source, style: &StrokeStyle, options: &DrawOptions) {
672        let tolerance = 0.1;
673
674        // Since we're flattening in userspace, we need to compensate for the transform otherwise
675        // we'll flatten too much or not enough depending on the scale. We approximate doing this
676        // correctly by scaling the tolerance value using the same mechanism as Fitz. This
677        // approximation will fail if the scale between axes is drastically different. An
678        // alternative would be to use transform specific flattening but I haven't seen that done
679        // anywhere.
680        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    /// Fills the rect `x`, `y,`, `width`, `height` with `src`. If the result is an
691    /// integer aligned rectangle performance will be faster than filling a rectangular path.
692    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    /// Fills `path` with `src`
716    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    /// Fills the current clip with the solid color `solid`
751    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 = Canvas::new(&euclid::Size2D::new(combined_bounds.size.width as u32,
833        combined_bounds.size.height as u32), Format::A8);*/
834        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    /// `mask_rect` is in DrawTarget space. i.e size is the size of the mask and origin is the position.
952    /// you can not render a part of the mask
953    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            // the transform is not invertible so we have nothing to draw
959            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    /// Draws `src_rect` of `src` at `dst`. The current transform and clip are ignored
1002    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        // intersect the src_rect with the source size so that we don't go out of bounds
1006        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        // clamp requires Float so open code it
1012        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    /// Draws `src_rect` of `src` at `dst`. The current transform and clip are ignored.
1029    /// `src_rect` is clamped to (0, 0, src.width, src.height).
1030    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    /// Blends `src_rect` of `src` at `dst`using `blend` mode.
1037    /// The current transform and clip are ignored.
1038    /// `src_rect` is clamped to (0, 0, `src.width`, `src.height`).
1039    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    /// Blends `src_rect` of `src` at `dst` using `alpha`. The current transform and clip are ignored.
1047    /// `src_rect` is clamped to (0, 0, `src.width`, `src.height`).
1048    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    /// Returns a reference to the underlying pixel data
1057    pub fn get_data(&self) -> &[u32] {
1058        self.buf.as_ref()
1059    }
1060
1061    /// Returns a mut reference to the underlying pixel data as ARGB with a representation
1062    /// like: (A << 24) | (R << 16) | (G << 8) | B
1063    pub fn get_data_mut(&mut self) -> &mut [u32] {
1064        self.buf.as_mut()
1065    }
1066
1067    /// Returns a reference to the underlying pixel data as individual bytes with the order BGRA
1068    /// on little endian.
1069    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        // we want to return an [u8] slice instead of a [u32] slice. This is a safe thing to
1074        // do because requirements of a [u32] slice are stricter.
1075        unsafe { std::slice::from_raw_parts(p as *const u8, len * std::mem::size_of::<u32>()) }
1076    }
1077
1078    /// Returns a mut reference to the underlying pixel data as individual bytes with the order BGRA
1079    /// on little endian.
1080    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        // we want to return an [u8] slice instead of a [u32] slice. This is a safe thing to
1085        // do because requirements of a [u32] slice are stricter.
1086        unsafe { std::slice::from_raw_parts_mut(p as *mut u8, len * std::mem::size_of::<u32>()) }
1087    }
1088
1089    /// Take ownership of the buffer backing the DrawTarget
1090    pub fn into_inner(self) -> Backing {
1091        self.buf
1092    }
1093
1094    /// Saves the current pixel to a png file at `path`
1095    #[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}