1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef MEDIAPROVIDER_PDF_JNI_PDFCLIENT_DOCUMENT_H_
18 #define MEDIAPROVIDER_PDF_JNI_PDFCLIENT_DOCUMENT_H_
19 
20 #define APPNAME "PdfViewerPdfClientLayer"
21 
22 #include <memory>
23 #include <unordered_map>
24 #include <utility>
25 
26 #include "cpp/fpdf_scopers.h"
27 #include "file.h"
28 #include "form_filler.h"
29 #include "fpdf_formfill.h"
30 #include "fpdfview.h"
31 #include "linux_fileops.h"
32 #include "page.h"
33 #include "rect.h"
34 
35 namespace pdfClient {
36 
37 // Status of an attempt to load a document. See Java's PdfStatus.
38 enum Status { NONE, REQUIRES_PASSWORD, LOADED, PDF_ERROR, FILE_ERROR, NEED_MORE_DATA };
39 
40 // Should be called once before using any other part of pdfClient.
41 void InitLibrary();
42 
43 // One PDF Document, mostly a wrapper around FPDF_Document. Automatically
44 // closes the FPDF_DOCUMENT when it is destroyed.
45 class Document {
46   public:
47     // Load the document from the given reader using the given password.
48     // If the returned status is LOADED, then a new Document is returned which
49     // now has ownership of the given FileReader.
50     // Any other status will not return a new Document and will not take
51     // ownership of the given FileReader or the underlying file.
52     // If the returned status is NEED_MORE_DATA, then the data that is needed
53     // will be indicated by a call to fileReader->RequestBlock.
54     static Status Load(std::unique_ptr<FileReader> fileReader, const char* password,
55                        bool closeFdOnFailure, std::unique_ptr<Document>* result,
56                        int* requestedHeaderSize = nullptr, int* requestedFooterSize = nullptr);
57 
58     // Wrap a FPDF_DOCUMENT in this Document, auto-close when this is destroyed.
Document(ScopedFPDFDocument document,bool is_password_protected)59     Document(ScopedFPDFDocument document, bool is_password_protected)
60         : Document(std::move(document), is_password_protected, nullptr, false, false) {}
61 
NumPages()62     int NumPages() const { return FPDF_GetPageCount(document_.get()); }
63 
GetFormType()64     int GetFormType() const { return FPDF_GetFormType(document_.get()); }
65 
66     /*
67      * Method to obtain a Page of the document.
68      *
69      * retain - Some operations will require the page be retained in memory.
70      * This is relevant to form filling where pages must be held by document in
71      * order to receive invalidated rectangles.
72      */
73     std::shared_ptr<Page> GetPage(int pageNum, bool retain = false);
74 
75     // @TODO(b/312222305): This call is only used for analytics, might go away when we
76     // implement quicker loading of linearized PDFs.
IsLinearized()77     bool IsLinearized() const { return is_linearized_; }
78 
IsPasswordProtected()79     bool IsPasswordProtected() const { return is_password_protected_; }
80 
ShouldScaleForPrinting()81     bool ShouldScaleForPrinting() const { return should_scale_for_printing_; }
82 
83     // FPDF_DOCUMENT is automatically closed when destroyed.
84     virtual ~Document();
85 
86     // Clone this document without security into the given file descriptor.
87     bool CloneDocumentWithoutSecurity(LinuxFileOps::FDCloser fd);
88 
89     // Save this Document to the given file descriptor, presumably opened for
90     // write or append. Return true on success.
91     bool SaveAs(LinuxFileOps::FDCloser fd);
92 
93     // Informs the document that the |rect| of the page bitmap has been
94     // invalidated for the given |page|. This takes place following form filling
95     // operations. |Rect| must be in page coordinates.
96     void NotifyInvalidRect(FPDF_PAGE page, Rectangle_i rect);
97 
98     // Removes the page from |pages_| and |fpdf_page_index_lookup_|, if retained,
99     // else no-op.
100     void ReleaseRetainedPage(int pageNum);
101 
102   private:
103     // Wrap a FPDF_DOCUMENT in this Document, auto-close when this is destroyed.
Document(ScopedFPDFDocument document,bool is_password_protected,std::unique_ptr<FileReader> file_reader,bool is_linearized,bool should_scale_for_printing)104     Document(ScopedFPDFDocument document, bool is_password_protected,
105              std::unique_ptr<FileReader> file_reader, bool is_linearized,
106              bool should_scale_for_printing)
107         : file_reader_(std::move(file_reader)),
108           document_(std::move(document)),
109           form_filler_(this, document_.get()),
110           is_password_protected_(is_password_protected),
111           is_linearized_(is_linearized),
112           should_scale_for_printing_(should_scale_for_printing) {}
113 
114     // Disable copy constructor because of the cleanup we do in ~Document.
115     Document(const Document&);
116 
117     // Returns true if the page is available. Always returns true if the document
118     // is not being loaded progressively. Should always be called before rendering
119     // or accessing the page - see http://b/21314248
120     bool IsPageAvailable(int pageNum) const;
121 
122     // Clone the document by simply copying the source file to the dest file.
123     bool CloneRawFile(int source, int dest);
124 
125     // Saves the loaded document back to a file (with security removed).
126     bool SaveAsCopyWithoutSecurity(LinuxFileOps::FDCloser dest);
127 
128     // If not null, this will also be deleted when this document is destroyed.
129     std::unique_ptr<FileReader> file_reader_;
130 
131     // document_, form_filler_ and pages_ must be initialized and torn down
132     // in this order for required resources to be available
133     ScopedFPDFDocument document_;
134     FormFiller form_filler_;
135     std::unordered_map<int, std::shared_ptr<Page>> pages_;
136 
137     // Map relating FPDF_PAGE to Page index for lookup.
138     // FPDF_PAGEs are not owned.
139     std::unordered_map<void*, int> fpdf_page_index_lookup_;
140 
141     // Whether the PDF is password protected.
142     bool is_password_protected_ = false;
143 
144     // Whether the PDF is linearized.
145     bool is_linearized_ = false;
146 
147     // Whether this PDF should be scaled for printing.
148     bool should_scale_for_printing_ = false;
149 };
150 
151 }  // namespace pdfClient
152 
153 #endif  // MEDIAPROVIDER_PDF_JNI_PDFCLIENT_DOCUMENT_H_