flo_canvas/
canvas.rs

1use crate::draw::*;
2use crate::color::*;
3use crate::context::*;
4use crate::draw_stream::*;
5
6use std::collections::{HashSet};
7use std::sync::*;
8use std::mem;
9use std::iter;
10
11use desync::{Desync};
12use futures::{Stream};
13use futures::task::{Waker};
14
15///
16/// The core of the canvas data structure
17///
18struct CanvasCore {
19    /// The main core contains the drawing instructions in this canvas: while DrawStreamCore is usually used for streaming
20    /// it can also be used to store the actions long-term (where the features that strip out unused actions and resources
21    /// are particularly useful)
22    main_core: DrawStreamCore,
23
24    /// Each stream created from the canvas has its own core (weak so we don't track the stream after it's been dropped)
25    streams: Vec<Weak<Desync<DrawStreamCore>>>
26}
27
28impl CanvasCore {
29    ///
30    /// Writes to the canvas core
31    ///
32    pub fn write(&mut self, actions: Vec<Draw>) -> Vec<Waker> {
33        // Write to the main core
34        self.main_core.write(actions.iter().cloned());
35
36        // Write to each of the streams
37        let mut remove_idx  = vec![];
38        let mut wakers      = vec![];
39
40        for (idx, stream) in self.streams.iter().enumerate() {
41            if let Some(stream) = stream.upgrade() {
42                wakers.push(stream.sync(|stream| {
43                    stream.write(iter::once(Draw::StartFrame));
44                    stream.write(actions.iter().cloned());
45                    stream.write(iter::once(Draw::ShowFrame));
46                    stream.take_waker()
47                }));
48            } else {
49                remove_idx.push(idx);
50            }
51        }
52
53        // Tidy any streams that are no longer listening
54        if remove_idx.len() > 0 {
55            let remove_idx  = remove_idx.into_iter().collect::<HashSet<_>>();
56            let old_streams = mem::take(&mut self.streams);
57
58            self.streams    = old_streams.into_iter()
59                .enumerate()
60                .filter(|(idx, _item)| !remove_idx.contains(idx))
61                .map(|(_idx, item)| item)
62                .collect();
63        }
64
65        // Return the wakers
66        wakers.into_iter().flatten().collect()
67    }
68}
69
70///
71/// A canvas is an abstract interface for drawing graphics. It doesn't actually provide a means to
72/// render anything, but rather a way to describe how things should be drawn and pass those on to
73/// a renderer elsewhere.
74///
75/// A canvas can be cloned and sent between threads, so it's possible for multiple sources to write
76/// to the same drawing target.
77///
78/// Canvases maintain a copy of enough of the drawing instructions sent to them to reproduce the
79/// rendering on a new render target. 
80///
81pub struct Canvas {
82    /// The canvas represents its own data using a draw stream core that's never used to generate a stream
83    core: Arc<Desync<CanvasCore>>
84}
85
86impl Canvas {
87    ///
88    /// Creates a new, blank, canvas
89    ///
90    pub fn new() -> Canvas {
91        // A canvas is initially just a clear command
92        let mut core = CanvasCore {
93            main_core:  DrawStreamCore::new(),
94            streams:    vec![]
95        };
96
97        core.main_core.add_usage();
98        core.main_core.write(vec![
99            Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))
100        ].into_iter());
101
102        Canvas {
103            core: Arc::new(Desync::new(core))
104        }
105    }
106
107    ///
108    /// Sends some new drawing commands to this canvas
109    ///
110    pub fn write(&self, to_draw: Vec<Draw>) {
111        // Only draw if there are any drawing commands
112        if to_draw.len() != 0 {
113            let wakers = self.core.sync(move |core| core.write(to_draw));
114            wakers.into_iter().for_each(|waker| waker.wake());
115        }
116    }
117
118    ///
119    /// Provides a way to draw on this canvas via a GC
120    ///
121    pub fn draw<FnAction>(&self, action: FnAction)
122    where FnAction: Send+FnOnce(&mut CanvasGraphicsContext) -> () {
123        self.core.sync(move |core| {
124            let mut graphics_context = CanvasGraphicsContext {
125                core:       core,
126                pending:    vec![]
127            };
128
129            action(&mut graphics_context);
130        })
131    }
132
133    ///
134    /// Creates a stream for reading the instructions from this canvas
135    ///
136    pub fn stream(&self) -> impl Stream<Item=Draw>+Send {
137        // Create a new canvas stream
138        let new_core    = Arc::new(Desync::new(DrawStreamCore::new()));
139        let new_stream  = DrawStream::with_core(&new_core);
140
141        // Register it and send the current set of pending commands to it
142        let add_stream = Arc::clone(&new_core);
143        self.core.desync(move |core| {
144            // Send the data we've received since the last clear
145            add_stream.sync(|stream| {
146                stream.write(iter::once(Draw::ResetFrame));
147                stream.write(core.main_core.get_pending_drawing())
148            });
149
150            // Store the stream in the core so future notifications get sent there
151            core.streams.push(Arc::downgrade(&add_stream));
152
153            // Wake the stream if it's not awake
154            add_stream.sync(|stream| stream.take_waker().map(|waker| waker.wake()));
155        });
156
157        // Return the new stream
158        new_stream
159    }
160
161    ///
162    /// Retrieves the list of drawing actions in this canvas
163    ///
164    pub fn get_drawing(&self) -> Vec<Draw> {
165        self.core.sync(|core| core.main_core.get_pending_drawing().collect())
166    }
167}
168
169impl Clone for Canvas {
170    fn clone(&self) -> Canvas {
171        self.core.desync(|core| core.main_core.add_usage());
172
173        Canvas {
174            core: self.core.clone()
175        }
176    }
177}
178
179impl Drop for Canvas {
180    fn drop(&mut self) {
181        // The streams drop if this is the last canvas with this core
182        self.core.sync(|core| {
183            if core.main_core.finish_usage() == 0 {
184                // Close all the streams and then wake them up
185                core.streams.drain(..)
186                    .map(|stream| {
187                        if let Some(stream) = stream.upgrade() {
188                            stream.sync(|stream| { stream.close(); stream.take_waker() })
189                        } else {
190                            None
191                        }
192                    })
193                    .flatten()
194                    .for_each(|waker| waker.wake());
195            }
196        });
197    }
198}
199
200///
201/// Graphics context for a Canvas
202///
203pub struct CanvasGraphicsContext<'a> {
204    core:       &'a mut CanvasCore,
205    pending:    Vec<Draw>
206}
207
208impl<'a> GraphicsContext for CanvasGraphicsContext<'a> {
209    fn draw(&mut self, d: Draw)                                 { self.pending.push(d); }
210}
211
212impl<'a> Drop for CanvasGraphicsContext<'a> {
213    fn drop(&mut self) {
214        let wakers = self.core.write(mem::take(&mut self.pending));
215        wakers.into_iter().for_each(|waker| waker.wake());
216    }
217}
218
219#[cfg(test)]
220mod test {
221    use super::*;
222    use crate::path::*;
223    use crate::font::*;
224    use crate::gradient::*;
225    use crate::font_face::*;
226    use crate::primitives::*;
227    use crate::transform2d::*;
228
229    use futures::prelude::*;
230    use futures::executor;
231
232    use std::thread::*;
233    use std::time::*;
234
235    #[test]
236    fn can_draw_to_canvas() {
237        let canvas = Canvas::new();
238
239        canvas.write(vec![Draw::Path(PathOp::NewPath)]);
240    }
241
242    #[test]
243    fn can_follow_canvas_stream() {
244        let canvas      = Canvas::new();
245        let mut stream  = canvas.stream();
246
247        // Thread to draw some stuff to the canvas
248        spawn(move || {
249            sleep(Duration::from_millis(50));
250
251            canvas.write(vec![
252                Draw::Path(PathOp::NewPath),
253                Draw::Path(PathOp::Move(0.0, 0.0)),
254                Draw::Path(PathOp::Line(10.0, 0.0)),
255                Draw::Path(PathOp::Line(10.0, 10.0)),
256                Draw::Path(PathOp::Line(0.0, 10.0))
257            ]);
258        });
259
260        // TODO: if the canvas fails to notify, this will block forever :-/
261
262        // Check we can get the results via the stream
263        executor::block_on(async {
264            assert!(stream.next().await == Some(Draw::ResetFrame));
265            assert!(stream.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))));
266            assert!(stream.next().await == Some(Draw::StartFrame));
267            assert!(stream.next().await == Some(Draw::Path(PathOp::NewPath)));
268            assert!(stream.next().await == Some(Draw::Path(PathOp::Move(0.0, 0.0))));
269            assert!(stream.next().await == Some(Draw::Path(PathOp::Line(10.0, 0.0))));
270            assert!(stream.next().await == Some(Draw::Path(PathOp::Line(10.0, 10.0))));
271            assert!(stream.next().await == Some(Draw::Path(PathOp::Line(0.0, 10.0))));
272            assert!(stream.next().await == Some(Draw::ShowFrame));
273
274            // When the thread goes away, it'll drop the canvas, so we should get the 'None' request here too
275            assert!(stream.next().await == None);
276        })
277    }
278
279    #[test]
280    fn can_draw_using_gc() {
281        let canvas      = Canvas::new();
282        let mut stream  = canvas.stream();
283
284        // Draw using a graphics context
285        canvas.draw(|gc| {
286            gc.new_path();
287            gc.move_to(0.0, 0.0);
288            gc.line_to(10.0, 0.0);
289            gc.line_to(10.0, 10.0);
290            gc.line_to(0.0, 10.0);
291        });
292
293        // Check we can get the results via the stream
294        executor::block_on(async {
295            assert!(stream.next().await == Some(Draw::ResetFrame));
296            assert!(stream.next().await == Some(Draw::StartFrame));
297            assert!(stream.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))));
298            assert!(stream.next().await == Some(Draw::Path(PathOp::NewPath)));
299            assert!(stream.next().await == Some(Draw::Path(PathOp::Move(0.0, 0.0))));
300            assert!(stream.next().await == Some(Draw::Path(PathOp::Line(10.0, 0.0))));
301            assert!(stream.next().await == Some(Draw::Path(PathOp::Line(10.0, 10.0))));
302            assert!(stream.next().await == Some(Draw::Path(PathOp::Line(0.0, 10.0))));
303            assert!(stream.next().await == Some(Draw::ShowFrame));
304        });
305    }
306
307    #[test]
308    fn restore_rewinds_canvas() {
309        let canvas      = Canvas::new();
310
311        // Draw using a graphics context
312        canvas.draw(|gc| {
313            gc.new_path();
314            gc.move_to(0.0, 0.0);
315            gc.line_to(10.0, 0.0);
316            gc.line_to(10.0, 10.0);
317            gc.line_to(0.0, 10.0);
318
319            gc.store();
320            gc.new_path();
321            gc.rect(0.0,0.0, 100.0,100.0);
322            gc.restore();
323
324            gc.stroke();
325        });
326
327        // Only the commands before the 'store' should be present
328        let mut stream  = canvas.stream();
329
330        executor::block_on(async {
331            assert!(stream.next().await == Some(Draw::ResetFrame));
332            assert!(stream.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))));
333            assert!(stream.next().await == Some(Draw::Path(PathOp::NewPath)));
334            assert!(stream.next().await == Some(Draw::Path(PathOp::Move(0.0, 0.0))));
335            assert!(stream.next().await == Some(Draw::Path(PathOp::Line(10.0, 0.0))));
336            assert!(stream.next().await == Some(Draw::Path(PathOp::Line(10.0, 10.0))));
337            assert!(stream.next().await == Some(Draw::Path(PathOp::Line(0.0, 10.0))));
338
339            // 'Store' is still present as we can restore the same thing repeatedly
340            assert!(stream.next().await == Some(Draw::Store));
341
342            assert!(stream.next().await == Some(Draw::Stroke));
343        })
344    }
345
346    #[test]
347    fn free_stored_buffer_after_restore() {
348        let canvas      = Canvas::new();
349
350        // Draw using a graphics context
351        canvas.draw(|gc| {
352            gc.new_path();
353            gc.move_to(0.0, 0.0);
354            gc.line_to(10.0, 0.0);
355            gc.line_to(10.0, 10.0);
356            gc.line_to(0.0, 10.0);
357
358            gc.store();
359            gc.new_path();
360            gc.rect(0.0,0.0, 100.0,100.0);
361            gc.restore();
362            gc.free_stored_buffer();
363
364            gc.stroke();
365        });
366
367        // Only the commands before the 'store' should be present
368        let mut stream  = canvas.stream();
369
370        executor::block_on(async
371        {
372            assert!(stream.next().await == Some(Draw::ResetFrame));
373            assert!(stream.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))));
374            assert!(stream.next().await == Some(Draw::Path(PathOp::NewPath)));
375            assert!(stream.next().await == Some(Draw::Path(PathOp::Move(0.0, 0.0))));
376            assert!(stream.next().await == Some(Draw::Path(PathOp::Line(10.0, 0.0))));
377            assert!(stream.next().await == Some(Draw::Path(PathOp::Line(10.0, 10.0))));
378            assert!(stream.next().await == Some(Draw::Path(PathOp::Line(0.0, 10.0))));
379
380            assert!(stream.next().await == Some(Draw::Stroke));
381        })
382    }
383
384    #[test]
385    fn clip_interrupts_rewind() {
386        let canvas      = Canvas::new();
387
388        // Draw using a graphics context
389        canvas.draw(|gc| {
390            gc.new_path();
391            gc.move_to(0.0, 0.0);
392            gc.line_to(10.0, 0.0);
393            gc.line_to(10.0, 10.0);
394            gc.line_to(0.0, 10.0);
395
396            gc.store();
397            gc.clip();
398            gc.new_path();
399            gc.restore();
400        });
401
402        // Only the commands before the 'store' should be present
403        let mut stream  = canvas.stream();
404        mem::drop(canvas);
405
406        executor::block_on(async {
407            assert!(stream.next().await == Some(Draw::ResetFrame));
408            assert!(stream.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))));
409            assert!(stream.next().await == Some(Draw::Path(PathOp::NewPath)));
410            assert!(stream.next().await == Some(Draw::Path(PathOp::Move(0.0, 0.0))));
411            assert!(stream.next().await == Some(Draw::Path(PathOp::Line(10.0, 0.0))));
412            assert!(stream.next().await == Some(Draw::Path(PathOp::Line(10.0, 10.0))));
413            assert!(stream.next().await == Some(Draw::Path(PathOp::Line(0.0, 10.0))));
414
415            assert!(stream.next().await == Some(Draw::Store));
416            assert!(stream.next().await == Some(Draw::Clip));
417            assert!(stream.next().await == Some(Draw::Path(PathOp::NewPath)));
418            assert!(stream.next().await == Some(Draw::Restore));
419        })
420    }
421
422    #[test]
423    fn can_follow_many_streams() {
424        let canvas      = Canvas::new();
425        let mut stream  = canvas.stream();
426        let mut stream2 = canvas.stream();
427
428        // Thread to draw some stuff to the canvas
429        spawn(move || {
430            sleep(Duration::from_millis(50));
431
432            canvas.write(vec![
433                Draw::Path(PathOp::NewPath),
434                Draw::Path(PathOp::Move(0.0, 0.0)),
435                Draw::Path(PathOp::Line(10.0, 0.0)),
436                Draw::Path(PathOp::Line(10.0, 10.0)),
437                Draw::Path(PathOp::Line(0.0, 10.0))
438            ]);
439        });
440
441        // TODO: if the canvas fails to notify, this will block forever :-/
442
443        executor::block_on(async {
444            // Check we can get the results via the stream
445            assert!(stream.next().await == Some(Draw::ResetFrame));
446            assert!(stream.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))));
447            assert!(stream.next().await == Some(Draw::StartFrame));
448            assert!(stream.next().await == Some(Draw::Path(PathOp::NewPath)));
449            assert!(stream.next().await == Some(Draw::Path(PathOp::Move(0.0, 0.0))));
450
451            assert!(stream2.next().await == Some(Draw::ResetFrame));
452            assert!(stream2.next().await == Some(Draw::StartFrame));
453            assert!(stream2.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))));
454            assert!(stream2.next().await == Some(Draw::Path(PathOp::NewPath)));
455            assert!(stream2.next().await == Some(Draw::Path(PathOp::Move(0.0, 0.0))));
456
457            assert!(stream.next().await == Some(Draw::Path(PathOp::Line(10.0, 0.0))));
458            assert!(stream.next().await == Some(Draw::Path(PathOp::Line(10.0, 10.0))));
459            assert!(stream.next().await == Some(Draw::Path(PathOp::Line(0.0, 10.0))));
460
461            assert!(stream2.next().await == Some(Draw::Path(PathOp::Line(10.0, 0.0))));
462            assert!(stream2.next().await == Some(Draw::Path(PathOp::Line(10.0, 10.0))));
463            assert!(stream2.next().await == Some(Draw::Path(PathOp::Line(0.0, 10.0))));
464
465            // When the thread goes away, it'll drop the canvas, so we should get the 'None' request here too
466            assert!(stream.next().await == Some(Draw::ShowFrame));
467            assert!(stream2.next().await == Some(Draw::ShowFrame));
468
469            assert!(stream.next().await == None);
470            assert!(stream2.next().await == None);
471        });
472    }
473
474    #[test]
475    fn commands_after_clear_are_suppressed() {
476        let canvas      = Canvas::new();
477        let mut stream  = canvas.stream();
478
479        // Thread to draw some stuff to the canvas
480        spawn(move || {
481            canvas.write(vec![
482                Draw::Path(PathOp::NewPath),
483                Draw::Path(PathOp::Move(0.0, 0.0)),
484                Draw::Path(PathOp::Line(10.0, 0.0)),
485                Draw::Path(PathOp::Line(10.0, 10.0)),
486                Draw::Path(PathOp::Line(0.0, 10.0))
487            ]);
488
489            // Enough time that we read the first few commands
490            sleep(Duration::from_millis(100));
491
492            canvas.write(vec![
493                Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 1.0)),
494                Draw::Path(PathOp::Move(200.0, 200.0)),
495            ]);
496        });
497
498        // TODO: if the canvas fails to notify, this will block forever :-/
499        executor::block_on(async {
500            // Give the thread some time to clear the canvas
501            sleep(Duration::from_millis(200));
502
503            // Should immediately stop the old frame and start a new one
504            assert!(stream.next().await == Some(Draw::ResetFrame));
505            assert!(stream.next().await == Some(Draw::StartFrame));
506
507            // Commands we sent before the flush are gone
508            assert!(stream.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 1.0))));
509            assert!(stream.next().await == Some(Draw::Path(PathOp::Move(200.0, 200.0))));
510            assert!(stream.next().await == Some(Draw::ShowFrame));
511
512            // When the thread goes away, it'll drop the canvas, so we should get the 'None' request here too
513            assert!(stream.next().await == None);
514        })
515    }
516
517    #[test]
518    fn clear_layer_0_removes_commands() {
519        let canvas      = Canvas::new();
520
521        // Draw using a graphics context
522        canvas.draw(|gc| {
523            gc.new_path();
524            gc.move_to(0.0, 0.0);
525            gc.line_to(10.0, 0.0);
526            gc.line_to(10.0, 10.0);
527            gc.line_to(0.0, 10.0);
528
529            gc.stroke();
530            gc.clear_layer();
531
532            gc.new_path();
533            gc.move_to(10.0, 10.0);
534            gc.fill();
535        });
536
537        // Only the commands after clear_layer should be present
538        let mut stream  = canvas.stream();
539
540        executor::block_on(async {
541            assert!(stream.next().await == Some(Draw::ResetFrame));
542            assert!(stream.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))));
543            assert!(stream.next().await == Some(Draw::Layer(LayerId(0))));
544            assert!(stream.next().await == Some(Draw::ClearLayer));
545            assert!(stream.next().await == Some(Draw::Path(PathOp::NewPath)));
546            assert!(stream.next().await == Some(Draw::Path(PathOp::Move(10.0, 10.0))));
547            assert!(stream.next().await == Some(Draw::Fill));
548        });
549    }
550
551    #[test]
552    fn clear_layer_only_removes_commands_for_the_current_layer() {
553        let canvas      = Canvas::new();
554
555        // Draw using a graphics context
556        canvas.draw(|gc| {
557            gc.new_path();
558            gc.move_to(20.0, 20.0);
559
560            gc.stroke();
561
562            gc.layer(LayerId(1));
563            gc.new_path();
564            gc.move_to(0.0, 0.0);
565            gc.line_to(10.0, 0.0);
566            gc.line_to(10.0, 10.0);
567            gc.line_to(0.0, 10.0);
568
569            gc.clear_layer();
570
571            gc.new_path();
572            gc.move_to(10.0, 10.0);
573            gc.fill();
574        });
575
576        // Only the commands after clear_layer should be present
577        let mut stream  = canvas.stream();
578
579        executor::block_on(async {
580            assert!(stream.next().await == Some(Draw::ResetFrame));
581            assert!(stream.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))));
582            assert!(stream.next().await == Some(Draw::Path(PathOp::NewPath)));
583            assert!(stream.next().await == Some(Draw::Path(PathOp::Move(20.0, 20.0))));
584            assert!(stream.next().await == Some(Draw::Stroke));
585
586            assert!(stream.next().await == Some(Draw::Layer(LayerId(1))));
587            assert!(stream.next().await == Some(Draw::ClearLayer));
588            assert!(stream.next().await == Some(Draw::Path(PathOp::NewPath)));
589            assert!(stream.next().await == Some(Draw::Path(PathOp::Move(10.0, 10.0))));
590            assert!(stream.next().await == Some(Draw::Fill));
591        });
592    }
593
594    #[test]
595    fn clear_layer_does_not_clear_sprites() {
596        let canvas      = Canvas::new();
597
598        // Draw using a graphics context
599        canvas.draw(|gc| {
600            gc.new_path();
601            gc.move_to(20.0, 20.0);
602
603            gc.stroke();
604
605            gc.layer(LayerId(1));
606            gc.new_path();
607            gc.move_to(0.0, 0.0);
608            gc.line_to(10.0, 0.0);
609            gc.line_to(10.0, 10.0);
610            gc.line_to(0.0, 10.0);
611
612            gc.sprite(SpriteId(1));
613            gc.clear_sprite();
614
615            gc.new_path();
616            gc.move_to(10.0, 10.0);
617            gc.fill();
618
619            gc.layer(LayerId(1));
620            gc.clear_layer();
621
622            gc.fill();
623        });
624
625        // Only the commands after clear_layer should be present
626        let mut stream  = canvas.stream();
627        println!("{:?}", canvas.get_drawing());
628
629        executor::block_on(async {
630            assert!(stream.next().await == Some(Draw::ResetFrame));
631            assert!(stream.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))));
632            assert!(stream.next().await == Some(Draw::Path(PathOp::NewPath)));
633            assert!(stream.next().await == Some(Draw::Path(PathOp::Move(20.0, 20.0))));
634            assert!(stream.next().await == Some(Draw::Stroke));
635
636            assert!(stream.next().await == Some(Draw::Sprite(SpriteId(1))));
637            assert!(stream.next().await == Some(Draw::ClearSprite));
638            assert!(stream.next().await == Some(Draw::Path(PathOp::NewPath)));
639            assert!(stream.next().await == Some(Draw::Path(PathOp::Move(10.0, 10.0))));
640            assert!(stream.next().await == Some(Draw::Fill));
641
642            assert!(stream.next().await == Some(Draw::Layer(LayerId(1))));
643            assert!(stream.next().await == Some(Draw::ClearLayer));
644            assert!(stream.next().await == Some(Draw::Fill));
645        });
646    }
647
648    #[test]
649    fn clear_layer_removes_pushed_transforms() {
650        let canvas      = Canvas::new();
651
652        // Draw using a graphics context
653        canvas.draw(|gc| {
654            gc.layer(LayerId(1));
655
656            gc.transform(Transform2D::identity());
657
658            gc.push_state();
659            gc.transform(Transform2D::scale(10.0, 10.0));
660            gc.pop_state();
661
662            gc.clear_layer();
663        });
664
665        // Only the commands after clear_layer should be present
666        let mut stream  = canvas.stream();
667        println!("{:?}", canvas.get_drawing());
668
669        executor::block_on(async {
670            assert!(stream.next().await == Some(Draw::ResetFrame));
671            assert!(stream.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))));
672            assert!(stream.next().await == Some(Draw::MultiplyTransform(Transform2D::identity())));
673            assert!(stream.next().await == Some(Draw::Layer(LayerId(1))));
674            assert!(stream.next().await == Some(Draw::ClearLayer));
675        });
676    }
677
678    #[test]
679    fn pushed_transforms_kept_in_order() {
680        let canvas      = Canvas::new();
681
682        // Draw using a graphics context
683        canvas.draw(|gc| {
684            gc.layer(LayerId(1));
685
686            gc.transform(Transform2D::identity());
687
688            gc.push_state();
689            gc.transform(Transform2D::scale(10.0, 10.0));
690
691            gc.clear_layer();
692        });
693
694        // Only the commands after clear_layer should be present
695        let mut stream  = canvas.stream();
696        println!("{:?}", canvas.get_drawing());
697
698        executor::block_on(async {
699            assert!(stream.next().await == Some(Draw::ResetFrame));
700            assert!(stream.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))));
701            assert!(stream.next().await == Some(Draw::MultiplyTransform(Transform2D::identity())));
702            assert!(stream.next().await == Some(Draw::PushState));
703            assert!(stream.next().await == Some(Draw::MultiplyTransform(Transform2D::scale(10.0, 10.0))));
704            assert!(stream.next().await == Some(Draw::Layer(LayerId(1))));
705            assert!(stream.next().await == Some(Draw::ClearLayer));
706        });
707    }
708
709    #[test]
710    fn font_definitions_survive_clear_layer() {
711        let canvas  = Canvas::new();
712        let lato    = CanvasFontFace::from_slice(include_bytes!("../test_data/Lato-Regular.ttf"));
713
714        canvas.draw(|gc| {
715            gc.layer(LayerId(1));
716
717            gc.define_font_data(FontId(1), lato.clone());
718            gc.set_font_size(FontId(1), 12.0);
719            gc.draw_text(FontId(1), "Test".to_string(), 100.0, 100.0);
720
721            gc.clear_layer();
722            gc.fill();
723        });
724
725        let mut stream = canvas.stream();
726
727        executor::block_on(async {
728            assert!(stream.next().await == Some(Draw::ResetFrame));
729            assert!(stream.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))));
730
731            assert!(match stream.next().await { Some(Draw::Font(FontId(1), FontOp::UseFontDefinition(_))) => true, _ => false });
732            assert!(stream.next().await == Some(Draw::Font(FontId(1), FontOp::FontSize(12.0))));
733
734            assert!(stream.next().await == Some(Draw::Layer(LayerId(1))));
735            assert!(stream.next().await == Some(Draw::ClearLayer));
736            assert!(stream.next().await == Some(Draw::Fill));
737        });
738    }
739
740    #[test]
741    fn only_one_font_definition_survives_clear_layer() {
742        let canvas  = Canvas::new();
743        let lato    = CanvasFontFace::from_slice(include_bytes!("../test_data/Lato-Regular.ttf"));
744
745        canvas.draw(|gc| {
746            gc.layer(LayerId(1));
747
748            gc.define_font_data(FontId(1), lato.clone());
749            gc.define_font_data(FontId(1), lato.clone());
750            gc.define_font_data(FontId(2), lato.clone());
751            gc.define_font_data(FontId(1), lato.clone());
752            gc.set_font_size(FontId(1), 12.0);
753            gc.draw_text(FontId(1), "Test".to_string(), 100.0, 100.0);
754
755            gc.clear_layer();
756            gc.fill();
757        });
758
759        let mut stream = canvas.stream();
760
761        executor::block_on(async {
762            assert!(stream.next().await == Some(Draw::ResetFrame));
763            assert!(stream.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))));
764
765            assert!(match stream.next().await { Some(Draw::Font(FontId(2), FontOp::UseFontDefinition(_))) => true, _ => false });
766            assert!(match stream.next().await { Some(Draw::Font(FontId(1), FontOp::UseFontDefinition(_))) => true, _ => false });
767            assert!(stream.next().await == Some(Draw::Font(FontId(1), FontOp::FontSize(12.0))));
768
769            assert!(stream.next().await == Some(Draw::Layer(LayerId(1))));
770            assert!(stream.next().await == Some(Draw::ClearLayer));
771            assert!(stream.next().await == Some(Draw::Fill));
772        });
773    }
774
775    #[test]
776    fn only_one_font_size_survives_clear_layer() {
777        let canvas  = Canvas::new();
778        let lato    = CanvasFontFace::from_slice(include_bytes!("../test_data/Lato-Regular.ttf"));
779
780        canvas.draw(|gc| {
781            gc.layer(LayerId(1));
782
783            gc.define_font_data(FontId(1), lato.clone());
784            gc.set_font_size(FontId(1), 16.0);
785            gc.set_font_size(FontId(1), 15.0);
786            gc.set_font_size(FontId(2), 18.0);
787            gc.set_font_size(FontId(1), 14.0);
788            gc.set_font_size(FontId(1), 13.0);
789            gc.set_font_size(FontId(1), 12.0);
790            gc.draw_text(FontId(1), "Test".to_string(), 100.0, 100.0);
791
792            gc.clear_layer();
793            gc.fill();
794        });
795
796        let mut stream = canvas.stream();
797
798        executor::block_on(async {
799            assert!(stream.next().await == Some(Draw::ResetFrame));
800            assert!(stream.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))));
801
802            assert!(match stream.next().await { Some(Draw::Font(FontId(1), FontOp::UseFontDefinition(_))) => true, _ => false });
803            assert!(stream.next().await == Some(Draw::Font(FontId(2), FontOp::FontSize(18.0))));
804            assert!(stream.next().await == Some(Draw::Font(FontId(1), FontOp::FontSize(12.0))));
805
806            assert!(stream.next().await == Some(Draw::Layer(LayerId(1))));
807            assert!(stream.next().await == Some(Draw::ClearLayer));
808            assert!(stream.next().await == Some(Draw::Fill));
809        });
810    }
811
812    #[test]
813    fn show_start_frames_cancel_out() {
814        let canvas  = Canvas::new();
815
816        canvas.draw(|gc| {
817            gc.clear_canvas(Color::Rgba(0.0, 0.0, 0.0, 0.0));
818
819            gc.start_frame();
820            gc.new_path();
821            gc.start_frame();
822            gc.move_to(20.0, 20.0);
823
824            gc.start_frame();
825            gc.stroke();
826
827            gc.start_frame();
828            gc.layer(LayerId(1));
829            gc.start_frame();
830            gc.new_path();
831            gc.start_frame();
832            gc.move_to(0.0, 0.0);
833            gc.start_frame();
834            gc.line_to(10.0, 0.0);
835            gc.start_frame();
836            gc.line_to(10.0, 10.0);
837            gc.start_frame();
838            gc.line_to(0.0, 10.0);
839
840            gc.start_frame();
841            gc.clear_layer();
842
843            gc.start_frame();
844            gc.new_path();
845            gc.start_frame();
846            gc.move_to(10.0, 10.0);
847            gc.start_frame();
848            gc.fill();
849
850            // Cancel all but one of the start frames
851            gc.show_frame();
852            gc.show_frame();
853            gc.show_frame();
854            gc.show_frame();
855            gc.show_frame();
856            gc.show_frame();
857            gc.show_frame();
858            gc.show_frame();
859            gc.show_frame();
860            gc.show_frame();
861            gc.show_frame();
862            gc.show_frame();
863        });
864
865        let mut stream = canvas.stream();
866
867        // Only the one uncanceled start_frame should be in the canvas
868        executor::block_on(async {
869            assert!(stream.next().await == Some(Draw::ResetFrame));
870            assert!(stream.next().await == Some(Draw::StartFrame));
871            assert!(stream.next().await == Some(Draw::StartFrame));
872            assert!(stream.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))));
873            assert!(stream.next().await == Some(Draw::Path(PathOp::NewPath)));
874            assert!(stream.next().await == Some(Draw::Path(PathOp::Move(20.0, 20.0))));
875            assert!(stream.next().await == Some(Draw::Stroke));
876
877            assert!(stream.next().await == Some(Draw::Layer(LayerId(1))));
878            assert!(stream.next().await == Some(Draw::ClearLayer));
879            assert!(stream.next().await == Some(Draw::Path(PathOp::NewPath)));
880            assert!(stream.next().await == Some(Draw::Path(PathOp::Move(10.0, 10.0))));
881            assert!(stream.next().await == Some(Draw::Fill));
882
883            assert!(stream.next().await == Some(Draw::ShowFrame));
884        });
885    }
886
887    #[test]
888    fn gradient_definitions_survive_clear_layer() {
889        let canvas  = Canvas::new();
890
891        canvas.draw(|gc| {
892            gc.layer(LayerId(1));
893
894            gc.create_gradient(GradientId(2), Color::Rgba(0.0, 0.1, 0.2, 0.3));
895            gc.gradient_stop(GradientId(2), 0.5, Color::Rgba(0.4, 0.5, 0.6, 1.0));
896            gc.gradient_stop(GradientId(2), 1.0, Color::Rgba(0.7, 0.8, 0.9, 1.0));
897
898            gc.clear_layer();
899            gc.fill();
900        });
901
902        let mut stream = canvas.stream();
903
904        executor::block_on(async {
905            assert!(stream.next().await == Some(Draw::ResetFrame));
906            assert!(stream.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))));
907
908            assert!(stream.next().await == Some(Draw::Gradient(GradientId(2), GradientOp::Create(Color::Rgba(0.0, 0.1, 0.2, 0.3)))));
909            assert!(stream.next().await == Some(Draw::Gradient(GradientId(2), GradientOp::AddStop(0.5, Color::Rgba(0.4, 0.5, 0.6, 1.0)))));
910            assert!(stream.next().await == Some(Draw::Gradient(GradientId(2), GradientOp::AddStop(1.0, Color::Rgba(0.7, 0.8, 0.9, 1.0)))));
911
912            assert!(stream.next().await == Some(Draw::Layer(LayerId(1))));
913            assert!(stream.next().await == Some(Draw::ClearLayer));
914            assert!(stream.next().await == Some(Draw::Fill));
915        });
916    }
917
918    #[test]
919    fn only_one_gradient_definition_survives_clear_layer() {
920        let canvas  = Canvas::new();
921
922        canvas.draw(|gc| {
923            gc.layer(LayerId(1));
924
925            gc.create_gradient(GradientId(2), Color::Rgba(0.0, 0.1, 0.2, 0.3));
926            gc.gradient_stop(GradientId(2), 0.5, Color::Rgba(0.4, 0.5, 0.6, 1.0));
927            gc.gradient_stop(GradientId(2), 1.0, Color::Rgba(0.7, 0.8, 0.9, 1.0));
928
929            gc.create_gradient(GradientId(2), Color::Rgba(0.0, 0.1, 0.2, 0.3));
930            gc.gradient_stop(GradientId(2), 0.5, Color::Rgba(0.4, 0.5, 0.6, 1.0));
931            gc.gradient_stop(GradientId(2), 1.0, Color::Rgba(0.7, 0.8, 0.9, 1.0));
932
933            gc.clear_layer();
934            gc.fill();
935        });
936
937        let mut stream = canvas.stream();
938
939        executor::block_on(async {
940            assert!(stream.next().await == Some(Draw::ResetFrame));
941            assert!(stream.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))));
942
943            assert!(stream.next().await == Some(Draw::Gradient(GradientId(2), GradientOp::Create(Color::Rgba(0.0, 0.1, 0.2, 0.3)))));
944            assert!(stream.next().await == Some(Draw::Gradient(GradientId(2), GradientOp::AddStop(0.5, Color::Rgba(0.4, 0.5, 0.6, 1.0)))));
945            assert!(stream.next().await == Some(Draw::Gradient(GradientId(2), GradientOp::AddStop(1.0, Color::Rgba(0.7, 0.8, 0.9, 1.0)))));
946
947            assert!(stream.next().await == Some(Draw::Layer(LayerId(1))));
948            assert!(stream.next().await == Some(Draw::ClearLayer));
949            assert!(stream.next().await == Some(Draw::Fill));
950        });
951    }
952
953    #[test]
954    fn only_one_gradient_definition_survives_clear_other_layer() {
955        let canvas  = Canvas::new();
956
957        canvas.draw(|gc| {
958            gc.layer(LayerId(0));
959
960            gc.create_gradient(GradientId(2), Color::Rgba(0.0, 0.1, 0.2, 0.3));
961            gc.gradient_stop(GradientId(2), 0.5, Color::Rgba(0.4, 0.5, 0.6, 1.0));
962            gc.gradient_stop(GradientId(2), 1.0, Color::Rgba(0.7, 0.8, 0.9, 1.0));
963
964            gc.create_gradient(GradientId(2), Color::Rgba(0.0, 0.1, 0.2, 0.3));
965            gc.gradient_stop(GradientId(2), 0.5, Color::Rgba(0.4, 0.5, 0.6, 1.0));
966            gc.gradient_stop(GradientId(2), 1.0, Color::Rgba(0.7, 0.8, 0.9, 1.0));
967
968            gc.layer(LayerId(1));
969            gc.clear_layer();
970            gc.fill();
971        });
972
973        let mut stream = canvas.stream();
974
975        executor::block_on(async {
976            assert!(stream.next().await == Some(Draw::ResetFrame));
977            assert!(stream.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))));
978
979            assert!(stream.next().await == Some(Draw::Layer(LayerId(0))));
980            assert!(stream.next().await == Some(Draw::Gradient(GradientId(2), GradientOp::Create(Color::Rgba(0.0, 0.1, 0.2, 0.3)))));
981            assert!(stream.next().await == Some(Draw::Gradient(GradientId(2), GradientOp::AddStop(0.5, Color::Rgba(0.4, 0.5, 0.6, 1.0)))));
982            assert!(stream.next().await == Some(Draw::Gradient(GradientId(2), GradientOp::AddStop(1.0, Color::Rgba(0.7, 0.8, 0.9, 1.0)))));
983
984            assert!(stream.next().await == Some(Draw::Layer(LayerId(1))));
985            assert!(stream.next().await == Some(Draw::ClearLayer));
986            assert!(stream.next().await == Some(Draw::Fill));
987        });
988    }
989
990    #[test]
991    fn used_gradient_survives_clear_other_layer() {
992        let canvas  = Canvas::new();
993
994        canvas.draw(|gc| {
995            gc.layer(LayerId(0));
996
997            gc.create_gradient(GradientId(2), Color::Rgba(0.0, 0.1, 0.2, 0.3));
998            gc.gradient_stop(GradientId(2), 0.5, Color::Rgba(0.4, 0.5, 0.6, 1.0));
999            gc.gradient_stop(GradientId(2), 1.0, Color::Rgba(0.7, 0.8, 0.9, 1.0));
1000
1001            gc.fill_gradient(GradientId(2), 0.0, 1.0, 2.0, 3.0);
1002
1003            gc.create_gradient(GradientId(2), Color::Rgba(0.0, 0.1, 0.2, 0.3));
1004            gc.gradient_stop(GradientId(2), 0.5, Color::Rgba(0.4, 0.5, 0.6, 1.0));
1005            gc.gradient_stop(GradientId(2), 1.0, Color::Rgba(0.7, 0.8, 0.9, 1.0));
1006
1007            gc.layer(LayerId(1));
1008            gc.clear_layer();
1009            gc.fill();
1010        });
1011
1012        let mut stream = canvas.stream();
1013
1014        executor::block_on(async {
1015            assert!(stream.next().await == Some(Draw::ResetFrame));
1016            assert!(stream.next().await == Some(Draw::ClearCanvas(Color::Rgba(0.0, 0.0, 0.0, 0.0))));
1017
1018            assert!(stream.next().await == Some(Draw::Layer(LayerId(0))));
1019
1020            assert!(stream.next().await == Some(Draw::Gradient(GradientId(2), GradientOp::Create(Color::Rgba(0.0, 0.1, 0.2, 0.3)))));
1021            assert!(stream.next().await == Some(Draw::Gradient(GradientId(2), GradientOp::AddStop(0.5, Color::Rgba(0.4, 0.5, 0.6, 1.0)))));
1022            assert!(stream.next().await == Some(Draw::Gradient(GradientId(2), GradientOp::AddStop(1.0, Color::Rgba(0.7, 0.8, 0.9, 1.0)))));
1023
1024            assert!(stream.next().await == Some(Draw::FillGradient(GradientId(2), (0.0, 1.0), (2.0, 3.0))));
1025
1026            assert!(stream.next().await == Some(Draw::Gradient(GradientId(2), GradientOp::Create(Color::Rgba(0.0, 0.1, 0.2, 0.3)))));
1027            assert!(stream.next().await == Some(Draw::Gradient(GradientId(2), GradientOp::AddStop(0.5, Color::Rgba(0.4, 0.5, 0.6, 1.0)))));
1028            assert!(stream.next().await == Some(Draw::Gradient(GradientId(2), GradientOp::AddStop(1.0, Color::Rgba(0.7, 0.8, 0.9, 1.0)))));
1029
1030            assert!(stream.next().await == Some(Draw::Layer(LayerId(1))));
1031            assert!(stream.next().await == Some(Draw::ClearLayer));
1032            assert!(stream.next().await == Some(Draw::Fill));
1033        });
1034    }
1035}