1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
pub mod pdf {
    use crate::interop::DynamicMemoryWStream;
    use crate::prelude::*;
    use crate::{scalar, DateTime, Document};
    use skia_bindings as sb;
    use skia_bindings::{SkPDF_Metadata, SkString};

    // TODO: DocumentStructureType
    // TODO: StructureElementNode

    #[derive(Clone, Debug, Default)]
    pub struct Metadata {
        pub title: String,
        pub author: String,
        pub subject: String,
        pub keywords: String,
        pub creator: String,
        pub producer: String,
        pub creation: Option<DateTime>,
        pub modified: Option<DateTime>,
        pub raster_dpi: Option<scalar>,
        pub pdfa: bool,
        pub encoding_quality: Option<i32>,
        // TODO: fStructureElementTreeRoot
    }

    // TODO: SetNodeId

    pub fn new_document(metadata: Option<&Metadata>) -> Document {
        let mut md = InternalMetadata::default();
        if let Some(metadata) = metadata {
            let internal = md.native_mut();
            internal.fTitle.set_s(&metadata.title);
            internal.fAuthor.set_s(&metadata.author);
            internal.fSubject.set_s(&metadata.subject);
            internal.fKeywords.set_s(&metadata.keywords);
            internal.fCreator.set_s(&metadata.creator);
            internal.fProducer.set_s(&metadata.producer);
            if let Some(creation) = metadata.creation {
                internal.fCreation = creation.into_native();
            }
            if let Some(modified) = metadata.modified {
                internal.fModified = modified.into_native();
            }
            if let Some(raster_dpi) = metadata.raster_dpi {
                internal.fRasterDPI = raster_dpi;
            }
            internal.fPDFA = metadata.pdfa;
            if let Some(encoding_quality) = metadata.encoding_quality {
                internal.fEncodingQuality = encoding_quality
            }
        }

        // we can't move the memory stream around anymore as soon it's referred by
        // the document.
        let mut memory_stream = Box::pin(DynamicMemoryWStream::new());
        let document = RCHandle::from_ptr(unsafe {
            sb::C_SkPDF_MakeDocument(&mut memory_stream.native_mut()._base, md.native())
        })
        .unwrap();

        Document::new(memory_stream, document)
    }

    //
    // Helper for constructing the internal metadata struct and setting associated strings.
    //

    type InternalMetadata = Handle<SkPDF_Metadata>;
    impl NativeDrop for SkPDF_Metadata {
        fn drop(&mut self) {
            unsafe { sb::C_SkPDF_Metadata_destruct(self) }
        }
    }

    impl Default for Handle<SkPDF_Metadata> {
        fn default() -> Self {
            Self::construct(|pdf_md| unsafe { sb::C_SkPDF_Metadata_Construct(pdf_md) })
        }
    }

    trait Set {
        fn set_s(&mut self, str: impl AsRef<str>);
    }

    impl Set for SkString {
        fn set_s(&mut self, str: impl AsRef<str>) {
            let bytes = str.as_ref().as_bytes();
            unsafe { self.set1(bytes.as_ptr() as _, bytes.len()) }
        }
    }
}