| 1 | use std::{fmt, ptr}; |
| 2 | |
| 3 | use skia_bindings::{self as sb, SkDocument, SkRefCntBase}; |
| 4 | |
| 5 | use crate::{interop::RustWStream, prelude::*, Canvas, Rect, Size}; |
| 6 | |
| 7 | pub struct Document<'a, State = state::Open> { |
| 8 | // Order matters here, first the document must be dropped _and then_ the stream. |
| 9 | document: RCHandle<SkDocument>, |
| 10 | stream: RustWStream<'a>, |
| 11 | |
| 12 | state: State, |
| 13 | } |
| 14 | |
| 15 | require_type_equality!(sb::SkDocument_INHERITED, sb::SkRefCnt); |
| 16 | |
| 17 | impl NativeRefCountedBase for SkDocument { |
| 18 | type Base = SkRefCntBase; |
| 19 | } |
| 20 | |
| 21 | impl<State: fmt::Debug> fmt::Debug for Document<'_, State> { |
| 22 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 23 | f&mut DebugStruct<'_, '_>.debug_struct("Document" ) |
| 24 | .field(name:"state" , &self.state) |
| 25 | .finish() |
| 26 | } |
| 27 | } |
| 28 | |
| 29 | pub mod state { |
| 30 | use std::{fmt, ptr}; |
| 31 | |
| 32 | use skia_bindings::SkCanvas; |
| 33 | |
| 34 | use crate::Canvas; |
| 35 | |
| 36 | /// Document is currently open. May contain several pages. |
| 37 | #[derive (Debug)] |
| 38 | pub struct Open { |
| 39 | pub(crate) pages: usize, |
| 40 | } |
| 41 | |
| 42 | /// Document is currently on a page and can be drawn onto. |
| 43 | pub struct OnPage { |
| 44 | pub(crate) page: usize, |
| 45 | pub(crate) canvas: ptr::NonNull<SkCanvas>, |
| 46 | } |
| 47 | |
| 48 | impl fmt::Debug for OnPage { |
| 49 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 50 | f.debug_struct("OnPage" ) |
| 51 | .field("page" , &self.page) |
| 52 | .field( |
| 53 | "canvas" , |
| 54 | Canvas::borrow_from_native(unsafe { self.canvas.as_ref() }), |
| 55 | ) |
| 56 | .finish() |
| 57 | } |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | impl<State> Document<'_, State> { |
| 62 | pub fn abort(mut self) { |
| 63 | unsafe { self.document.native_mut().abort() } |
| 64 | drop(self) |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | impl<'a> Document<'a, state::Open> { |
| 69 | pub(crate) fn new(stream: RustWStream<'a>, document: RCHandle<SkDocument>) -> Self { |
| 70 | Document { |
| 71 | document, |
| 72 | stream, |
| 73 | state: state::Open { pages: 0 }, |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | /// The number of pages in this document. |
| 78 | pub fn pages(&self) -> usize { |
| 79 | self.state.pages |
| 80 | } |
| 81 | |
| 82 | // This function consumes the document and returns a document containing a |
| 83 | // canvas that represents the page it's currently drawing on. |
| 84 | pub fn begin_page( |
| 85 | mut self, |
| 86 | size: impl Into<Size>, |
| 87 | content: Option<&Rect>, |
| 88 | ) -> Document<'a, state::OnPage> { |
| 89 | let size = size.into(); |
| 90 | let canvas = unsafe { |
| 91 | self.document.native_mut().beginPage( |
| 92 | size.width, |
| 93 | size.height, |
| 94 | content.native_ptr_or_null(), |
| 95 | ) |
| 96 | }; |
| 97 | |
| 98 | Document { |
| 99 | stream: self.stream, |
| 100 | document: self.document, |
| 101 | state: state::OnPage { |
| 102 | canvas: ptr::NonNull::new(canvas).unwrap(), |
| 103 | page: self.state.pages + 1, |
| 104 | }, |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | /// Close the document and return the encoded representation. |
| 109 | /// |
| 110 | /// This function consumes and drops the document. |
| 111 | pub fn close(mut self) { |
| 112 | unsafe { |
| 113 | self.document.native_mut().close(); |
| 114 | }; |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | impl<'a> Document<'a, state::OnPage> { |
| 119 | /// The current page we are currently drawing on. |
| 120 | pub fn page(&self) -> usize { |
| 121 | self.state.page |
| 122 | } |
| 123 | |
| 124 | /// Borrows the canvas for the current page on the document. |
| 125 | pub fn canvas(&mut self) -> &Canvas { |
| 126 | Canvas::borrow_from_native(unsafe { self.state.canvas.as_ref() }) |
| 127 | } |
| 128 | |
| 129 | /// Ends the page. |
| 130 | /// |
| 131 | /// This function consumes the document and returns a new open document that |
| 132 | /// contains the pages drawn so far. |
| 133 | pub fn end_page(mut self) -> Document<'a> { |
| 134 | unsafe { |
| 135 | self.document.native_mut().endPage(); |
| 136 | } |
| 137 | |
| 138 | Document { |
| 139 | stream: self.stream, |
| 140 | document: self.document, |
| 141 | state: state::Open { |
| 142 | pages: self.state.page, |
| 143 | }, |
| 144 | } |
| 145 | |
| 146 | // TODO: Think about providing a close() function that implicitly ends the page |
| 147 | // and calls close() on the Open document. |
| 148 | // TODO: Think about providing a begin_page() function that implicitly ends the |
| 149 | // current page. |
| 150 | } |
| 151 | } |
| 152 | |