xref: /aosp_15_r20/external/pdfium/samples/pdfium_test.cc (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2010 The PDFium Authors
2*3ac0a46fSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*3ac0a46fSAndroid Build Coastguard Worker // found in the LICENSE file.
4*3ac0a46fSAndroid Build Coastguard Worker 
5*3ac0a46fSAndroid Build Coastguard Worker #include <locale.h>
6*3ac0a46fSAndroid Build Coastguard Worker #include <stddef.h>
7*3ac0a46fSAndroid Build Coastguard Worker #include <stdint.h>
8*3ac0a46fSAndroid Build Coastguard Worker #include <stdio.h>
9*3ac0a46fSAndroid Build Coastguard Worker #include <stdlib.h>
10*3ac0a46fSAndroid Build Coastguard Worker #include <string.h>
11*3ac0a46fSAndroid Build Coastguard Worker 
12*3ac0a46fSAndroid Build Coastguard Worker #include <functional>
13*3ac0a46fSAndroid Build Coastguard Worker #include <iterator>
14*3ac0a46fSAndroid Build Coastguard Worker #include <map>
15*3ac0a46fSAndroid Build Coastguard Worker #include <memory>
16*3ac0a46fSAndroid Build Coastguard Worker #include <sstream>
17*3ac0a46fSAndroid Build Coastguard Worker #include <string>
18*3ac0a46fSAndroid Build Coastguard Worker #include <vector>
19*3ac0a46fSAndroid Build Coastguard Worker 
20*3ac0a46fSAndroid Build Coastguard Worker #if defined(PDF_ENABLE_SKIA) && !defined(_SKIA_SUPPORT_)
21*3ac0a46fSAndroid Build Coastguard Worker #define _SKIA_SUPPORT_
22*3ac0a46fSAndroid Build Coastguard Worker #endif
23*3ac0a46fSAndroid Build Coastguard Worker 
24*3ac0a46fSAndroid Build Coastguard Worker #include "public/cpp/fpdf_scopers.h"
25*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_annot.h"
26*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_attachment.h"
27*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_dataavail.h"
28*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_edit.h"
29*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_ext.h"
30*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_formfill.h"
31*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_progressive.h"
32*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_structtree.h"
33*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_text.h"
34*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdfview.h"
35*3ac0a46fSAndroid Build Coastguard Worker #include "samples/helpers/dump.h"
36*3ac0a46fSAndroid Build Coastguard Worker #include "samples/helpers/event.h"
37*3ac0a46fSAndroid Build Coastguard Worker #include "samples/helpers/page_renderer.h"
38*3ac0a46fSAndroid Build Coastguard Worker #include "samples/helpers/write.h"
39*3ac0a46fSAndroid Build Coastguard Worker #include "testing/command_line_helpers.h"
40*3ac0a46fSAndroid Build Coastguard Worker #include "testing/font_renamer.h"
41*3ac0a46fSAndroid Build Coastguard Worker #include "testing/fx_string_testhelpers.h"
42*3ac0a46fSAndroid Build Coastguard Worker #include "testing/test_loader.h"
43*3ac0a46fSAndroid Build Coastguard Worker #include "testing/utils/file_util.h"
44*3ac0a46fSAndroid Build Coastguard Worker #include "testing/utils/hash.h"
45*3ac0a46fSAndroid Build Coastguard Worker #include "testing/utils/path_service.h"
46*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/abseil-cpp/absl/types/optional.h"
47*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/check_op.h"
48*3ac0a46fSAndroid Build Coastguard Worker 
49*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
50*3ac0a46fSAndroid Build Coastguard Worker #include <crtdbg.h>
51*3ac0a46fSAndroid Build Coastguard Worker #include <errhandlingapi.h>
52*3ac0a46fSAndroid Build Coastguard Worker #include <io.h>
53*3ac0a46fSAndroid Build Coastguard Worker #include <wingdi.h>
54*3ac0a46fSAndroid Build Coastguard Worker 
55*3ac0a46fSAndroid Build Coastguard Worker #include "samples/helpers/win32/com_factory.h"
56*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/win/scoped_select_object.h"
57*3ac0a46fSAndroid Build Coastguard Worker #else
58*3ac0a46fSAndroid Build Coastguard Worker #include <unistd.h>
59*3ac0a46fSAndroid Build Coastguard Worker #endif  // _WIN32
60*3ac0a46fSAndroid Build Coastguard Worker 
61*3ac0a46fSAndroid Build Coastguard Worker #ifdef ENABLE_CALLGRIND
62*3ac0a46fSAndroid Build Coastguard Worker #include <valgrind/callgrind.h>
63*3ac0a46fSAndroid Build Coastguard Worker #endif  // ENABLE_CALLGRIND
64*3ac0a46fSAndroid Build Coastguard Worker 
65*3ac0a46fSAndroid Build Coastguard Worker #if defined(PDF_USE_PARTITION_ALLOC)
66*3ac0a46fSAndroid Build Coastguard Worker #include "testing/allocator_shim_config.h"
67*3ac0a46fSAndroid Build Coastguard Worker #endif
68*3ac0a46fSAndroid Build Coastguard Worker 
69*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_SKIA
70*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/skia/include/core/SkCanvas.h"           // nogncheck
71*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/skia/include/core/SkColor.h"            // nogncheck
72*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/skia/include/core/SkDocument.h"         // nogncheck
73*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/skia/include/core/SkPicture.h"          // nogncheck
74*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/skia/include/core/SkPictureRecorder.h"  // nogncheck
75*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/skia/include/core/SkPixmap.h"           // nogncheck
76*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/skia/include/core/SkRefCnt.h"           // nogncheck
77*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/skia/include/core/SkStream.h"           // nogncheck
78*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/skia/include/core/SkSurface.h"          // nogncheck
79*3ac0a46fSAndroid Build Coastguard Worker 
80*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
81*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/skia/include/docs/SkXPSDocument.h"  // nogncheck
82*3ac0a46fSAndroid Build Coastguard Worker #endif
83*3ac0a46fSAndroid Build Coastguard Worker 
84*3ac0a46fSAndroid Build Coastguard Worker #ifdef BUILD_WITH_CHROMIUM
85*3ac0a46fSAndroid Build Coastguard Worker #include "samples/chromium_support/discardable_memory_allocator.h"  // nogncheck
86*3ac0a46fSAndroid Build Coastguard Worker #endif
87*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_SKIA
88*3ac0a46fSAndroid Build Coastguard Worker 
89*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_V8
90*3ac0a46fSAndroid Build Coastguard Worker #include "testing/v8_initializer.h"
91*3ac0a46fSAndroid Build Coastguard Worker #include "v8/include/libplatform/libplatform.h"
92*3ac0a46fSAndroid Build Coastguard Worker #include "v8/include/v8-array-buffer.h"
93*3ac0a46fSAndroid Build Coastguard Worker #include "v8/include/v8-isolate.h"
94*3ac0a46fSAndroid Build Coastguard Worker #include "v8/include/v8-platform.h"
95*3ac0a46fSAndroid Build Coastguard Worker #include "v8/include/v8-snapshot.h"
96*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_V8
97*3ac0a46fSAndroid Build Coastguard Worker 
98*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
99*3ac0a46fSAndroid Build Coastguard Worker #define access _access
100*3ac0a46fSAndroid Build Coastguard Worker #define snprintf _snprintf
101*3ac0a46fSAndroid Build Coastguard Worker #define R_OK 4
102*3ac0a46fSAndroid Build Coastguard Worker #endif
103*3ac0a46fSAndroid Build Coastguard Worker 
104*3ac0a46fSAndroid Build Coastguard Worker // wordexp is a POSIX function that is only available on macOS and non-Android
105*3ac0a46fSAndroid Build Coastguard Worker // Linux platforms.
106*3ac0a46fSAndroid Build Coastguard Worker #if defined(__APPLE__) || (defined(__linux__) && !defined(__ANDROID__))
107*3ac0a46fSAndroid Build Coastguard Worker #define WORDEXP_AVAILABLE
108*3ac0a46fSAndroid Build Coastguard Worker #endif
109*3ac0a46fSAndroid Build Coastguard Worker 
110*3ac0a46fSAndroid Build Coastguard Worker #ifdef WORDEXP_AVAILABLE
111*3ac0a46fSAndroid Build Coastguard Worker #include <wordexp.h>
112*3ac0a46fSAndroid Build Coastguard Worker #endif  // WORDEXP_AVAILABLE
113*3ac0a46fSAndroid Build Coastguard Worker 
114*3ac0a46fSAndroid Build Coastguard Worker namespace {
115*3ac0a46fSAndroid Build Coastguard Worker 
116*3ac0a46fSAndroid Build Coastguard Worker enum class RendererType {
117*3ac0a46fSAndroid Build Coastguard Worker   kDefault,
118*3ac0a46fSAndroid Build Coastguard Worker   kAgg,
119*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
120*3ac0a46fSAndroid Build Coastguard Worker   kGdi,
121*3ac0a46fSAndroid Build Coastguard Worker #endif  // _WIN32
122*3ac0a46fSAndroid Build Coastguard Worker #if defined(PDF_ENABLE_SKIA)
123*3ac0a46fSAndroid Build Coastguard Worker   kSkia,
124*3ac0a46fSAndroid Build Coastguard Worker #endif  // defined(PDF_ENABLE_SKIA)
125*3ac0a46fSAndroid Build Coastguard Worker };
126*3ac0a46fSAndroid Build Coastguard Worker 
127*3ac0a46fSAndroid Build Coastguard Worker enum class OutputFormat {
128*3ac0a46fSAndroid Build Coastguard Worker   kNone,
129*3ac0a46fSAndroid Build Coastguard Worker   kPageInfo,
130*3ac0a46fSAndroid Build Coastguard Worker   kStructure,
131*3ac0a46fSAndroid Build Coastguard Worker   kText,
132*3ac0a46fSAndroid Build Coastguard Worker   kPpm,
133*3ac0a46fSAndroid Build Coastguard Worker   kPng,
134*3ac0a46fSAndroid Build Coastguard Worker   kAnnot,
135*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
136*3ac0a46fSAndroid Build Coastguard Worker   kBmp,
137*3ac0a46fSAndroid Build Coastguard Worker   kEmf,
138*3ac0a46fSAndroid Build Coastguard Worker   kPs2,
139*3ac0a46fSAndroid Build Coastguard Worker   kPs3,
140*3ac0a46fSAndroid Build Coastguard Worker   kPs3Type42,
141*3ac0a46fSAndroid Build Coastguard Worker #endif
142*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_SKIA
143*3ac0a46fSAndroid Build Coastguard Worker   kSkp,
144*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
145*3ac0a46fSAndroid Build Coastguard Worker   kXps,
146*3ac0a46fSAndroid Build Coastguard Worker #endif  // _WIN32
147*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_SKIA
148*3ac0a46fSAndroid Build Coastguard Worker };
149*3ac0a46fSAndroid Build Coastguard Worker 
150*3ac0a46fSAndroid Build Coastguard Worker struct Options {
151*3ac0a46fSAndroid Build Coastguard Worker   Options() = default;
152*3ac0a46fSAndroid Build Coastguard Worker 
153*3ac0a46fSAndroid Build Coastguard Worker   bool show_config = false;
154*3ac0a46fSAndroid Build Coastguard Worker   bool show_metadata = false;
155*3ac0a46fSAndroid Build Coastguard Worker   bool send_events = false;
156*3ac0a46fSAndroid Build Coastguard Worker   bool use_load_mem_document = false;
157*3ac0a46fSAndroid Build Coastguard Worker   bool render_oneshot = false;
158*3ac0a46fSAndroid Build Coastguard Worker   bool lcd_text = false;
159*3ac0a46fSAndroid Build Coastguard Worker   bool no_nativetext = false;
160*3ac0a46fSAndroid Build Coastguard Worker   bool grayscale = false;
161*3ac0a46fSAndroid Build Coastguard Worker   bool forced_color = false;
162*3ac0a46fSAndroid Build Coastguard Worker   bool fill_to_stroke = false;
163*3ac0a46fSAndroid Build Coastguard Worker   bool limit_cache = false;
164*3ac0a46fSAndroid Build Coastguard Worker   bool force_halftone = false;
165*3ac0a46fSAndroid Build Coastguard Worker   bool printing = false;
166*3ac0a46fSAndroid Build Coastguard Worker   bool no_smoothtext = false;
167*3ac0a46fSAndroid Build Coastguard Worker   bool no_smoothimage = false;
168*3ac0a46fSAndroid Build Coastguard Worker   bool no_smoothpath = false;
169*3ac0a46fSAndroid Build Coastguard Worker   bool reverse_byte_order = false;
170*3ac0a46fSAndroid Build Coastguard Worker   bool save_attachments = false;
171*3ac0a46fSAndroid Build Coastguard Worker   bool save_images = false;
172*3ac0a46fSAndroid Build Coastguard Worker   bool save_rendered_images = false;
173*3ac0a46fSAndroid Build Coastguard Worker   bool save_thumbnails = false;
174*3ac0a46fSAndroid Build Coastguard Worker   bool save_thumbnails_decoded = false;
175*3ac0a46fSAndroid Build Coastguard Worker   bool save_thumbnails_raw = false;
176*3ac0a46fSAndroid Build Coastguard Worker   RendererType use_renderer_type = RendererType::kDefault;
177*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_V8
178*3ac0a46fSAndroid Build Coastguard Worker   bool disable_javascript = false;
179*3ac0a46fSAndroid Build Coastguard Worker   std::string js_flags;  // Extra flags to pass to v8 init.
180*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_XFA
181*3ac0a46fSAndroid Build Coastguard Worker   bool disable_xfa = false;
182*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_XFA
183*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_V8
184*3ac0a46fSAndroid Build Coastguard Worker   bool pages = false;
185*3ac0a46fSAndroid Build Coastguard Worker   bool md5 = false;
186*3ac0a46fSAndroid Build Coastguard Worker #ifdef ENABLE_CALLGRIND
187*3ac0a46fSAndroid Build Coastguard Worker   bool callgrind_delimiters = false;
188*3ac0a46fSAndroid Build Coastguard Worker #endif
189*3ac0a46fSAndroid Build Coastguard Worker #if defined(__APPLE__) || (defined(__linux__) && !defined(__ANDROID__))
190*3ac0a46fSAndroid Build Coastguard Worker   bool linux_no_system_fonts = false;
191*3ac0a46fSAndroid Build Coastguard Worker #endif
192*3ac0a46fSAndroid Build Coastguard Worker   bool croscore_font_names = false;
193*3ac0a46fSAndroid Build Coastguard Worker   OutputFormat output_format = OutputFormat::kNone;
194*3ac0a46fSAndroid Build Coastguard Worker   std::string password;
195*3ac0a46fSAndroid Build Coastguard Worker   std::string scale_factor_as_string;
196*3ac0a46fSAndroid Build Coastguard Worker   std::string exe_path;
197*3ac0a46fSAndroid Build Coastguard Worker   std::string bin_directory;
198*3ac0a46fSAndroid Build Coastguard Worker   std::string font_directory;
199*3ac0a46fSAndroid Build Coastguard Worker   int first_page = 0;  // First 0-based page number to renderer.
200*3ac0a46fSAndroid Build Coastguard Worker   int last_page = 0;   // Last 0-based page number to renderer.
201*3ac0a46fSAndroid Build Coastguard Worker   time_t time = -1;
202*3ac0a46fSAndroid Build Coastguard Worker };
203*3ac0a46fSAndroid Build Coastguard Worker 
PageRenderFlagsFromOptions(const Options & options)204*3ac0a46fSAndroid Build Coastguard Worker int PageRenderFlagsFromOptions(const Options& options) {
205*3ac0a46fSAndroid Build Coastguard Worker   int flags = FPDF_ANNOT;
206*3ac0a46fSAndroid Build Coastguard Worker   if (options.lcd_text)
207*3ac0a46fSAndroid Build Coastguard Worker     flags |= FPDF_LCD_TEXT;
208*3ac0a46fSAndroid Build Coastguard Worker   if (options.no_nativetext)
209*3ac0a46fSAndroid Build Coastguard Worker     flags |= FPDF_NO_NATIVETEXT;
210*3ac0a46fSAndroid Build Coastguard Worker   if (options.grayscale)
211*3ac0a46fSAndroid Build Coastguard Worker     flags |= FPDF_GRAYSCALE;
212*3ac0a46fSAndroid Build Coastguard Worker   if (options.fill_to_stroke)
213*3ac0a46fSAndroid Build Coastguard Worker     flags |= FPDF_CONVERT_FILL_TO_STROKE;
214*3ac0a46fSAndroid Build Coastguard Worker   if (options.limit_cache)
215*3ac0a46fSAndroid Build Coastguard Worker     flags |= FPDF_RENDER_LIMITEDIMAGECACHE;
216*3ac0a46fSAndroid Build Coastguard Worker   if (options.force_halftone)
217*3ac0a46fSAndroid Build Coastguard Worker     flags |= FPDF_RENDER_FORCEHALFTONE;
218*3ac0a46fSAndroid Build Coastguard Worker   if (options.printing)
219*3ac0a46fSAndroid Build Coastguard Worker     flags |= FPDF_PRINTING;
220*3ac0a46fSAndroid Build Coastguard Worker   if (options.no_smoothtext)
221*3ac0a46fSAndroid Build Coastguard Worker     flags |= FPDF_RENDER_NO_SMOOTHTEXT;
222*3ac0a46fSAndroid Build Coastguard Worker   if (options.no_smoothimage)
223*3ac0a46fSAndroid Build Coastguard Worker     flags |= FPDF_RENDER_NO_SMOOTHIMAGE;
224*3ac0a46fSAndroid Build Coastguard Worker   if (options.no_smoothpath)
225*3ac0a46fSAndroid Build Coastguard Worker     flags |= FPDF_RENDER_NO_SMOOTHPATH;
226*3ac0a46fSAndroid Build Coastguard Worker   if (options.reverse_byte_order)
227*3ac0a46fSAndroid Build Coastguard Worker     flags |= FPDF_REVERSE_BYTE_ORDER;
228*3ac0a46fSAndroid Build Coastguard Worker   return flags;
229*3ac0a46fSAndroid Build Coastguard Worker }
230*3ac0a46fSAndroid Build Coastguard Worker 
ExpandDirectoryPath(const std::string & path)231*3ac0a46fSAndroid Build Coastguard Worker absl::optional<std::string> ExpandDirectoryPath(const std::string& path) {
232*3ac0a46fSAndroid Build Coastguard Worker #if defined(WORDEXP_AVAILABLE)
233*3ac0a46fSAndroid Build Coastguard Worker   wordexp_t expansion;
234*3ac0a46fSAndroid Build Coastguard Worker   if (wordexp(path.c_str(), &expansion, 0) != 0 || expansion.we_wordc < 1) {
235*3ac0a46fSAndroid Build Coastguard Worker     wordfree(&expansion);
236*3ac0a46fSAndroid Build Coastguard Worker     return {};
237*3ac0a46fSAndroid Build Coastguard Worker   }
238*3ac0a46fSAndroid Build Coastguard Worker   // Need to contruct the return value before hand, since wordfree will
239*3ac0a46fSAndroid Build Coastguard Worker   // deallocate |expansion|.
240*3ac0a46fSAndroid Build Coastguard Worker   absl::optional<std::string> ret_val = {expansion.we_wordv[0]};
241*3ac0a46fSAndroid Build Coastguard Worker   wordfree(&expansion);
242*3ac0a46fSAndroid Build Coastguard Worker   return ret_val;
243*3ac0a46fSAndroid Build Coastguard Worker #else
244*3ac0a46fSAndroid Build Coastguard Worker   return {path};
245*3ac0a46fSAndroid Build Coastguard Worker #endif  // WORDEXP_AVAILABLE
246*3ac0a46fSAndroid Build Coastguard Worker }
247*3ac0a46fSAndroid Build Coastguard Worker 
GetCustomFontPath(const Options & options)248*3ac0a46fSAndroid Build Coastguard Worker absl::optional<const char*> GetCustomFontPath(const Options& options) {
249*3ac0a46fSAndroid Build Coastguard Worker #if defined(__APPLE__) || (defined(__linux__) && !defined(__ANDROID__))
250*3ac0a46fSAndroid Build Coastguard Worker   // Set custom font path to an empty path. This avoids the fallback to default
251*3ac0a46fSAndroid Build Coastguard Worker   // font paths.
252*3ac0a46fSAndroid Build Coastguard Worker   if (options.linux_no_system_fonts)
253*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
254*3ac0a46fSAndroid Build Coastguard Worker #endif
255*3ac0a46fSAndroid Build Coastguard Worker 
256*3ac0a46fSAndroid Build Coastguard Worker   // No custom font path. Use default.
257*3ac0a46fSAndroid Build Coastguard Worker   if (options.font_directory.empty())
258*3ac0a46fSAndroid Build Coastguard Worker     return absl::nullopt;
259*3ac0a46fSAndroid Build Coastguard Worker 
260*3ac0a46fSAndroid Build Coastguard Worker   // Set custom font path to |options.font_directory|.
261*3ac0a46fSAndroid Build Coastguard Worker   return options.font_directory.c_str();
262*3ac0a46fSAndroid Build Coastguard Worker }
263*3ac0a46fSAndroid Build Coastguard Worker 
264*3ac0a46fSAndroid Build Coastguard Worker struct FPDF_FORMFILLINFO_PDFiumTest final : public FPDF_FORMFILLINFO {
265*3ac0a46fSAndroid Build Coastguard Worker   // Hold a map of the currently loaded pages in order to avoid them
266*3ac0a46fSAndroid Build Coastguard Worker   // to get loaded twice.
267*3ac0a46fSAndroid Build Coastguard Worker   std::map<int, ScopedFPDFPage> loaded_pages;
268*3ac0a46fSAndroid Build Coastguard Worker 
269*3ac0a46fSAndroid Build Coastguard Worker   // Hold a pointer of FPDF_FORMHANDLE so that PDFium app hooks can
270*3ac0a46fSAndroid Build Coastguard Worker   // make use of it.
271*3ac0a46fSAndroid Build Coastguard Worker   FPDF_FORMHANDLE form_handle;
272*3ac0a46fSAndroid Build Coastguard Worker };
273*3ac0a46fSAndroid Build Coastguard Worker 
ToPDFiumTestFormFillInfo(FPDF_FORMFILLINFO * form_fill_info)274*3ac0a46fSAndroid Build Coastguard Worker FPDF_FORMFILLINFO_PDFiumTest* ToPDFiumTestFormFillInfo(
275*3ac0a46fSAndroid Build Coastguard Worker     FPDF_FORMFILLINFO* form_fill_info) {
276*3ac0a46fSAndroid Build Coastguard Worker   return static_cast<FPDF_FORMFILLINFO_PDFiumTest*>(form_fill_info);
277*3ac0a46fSAndroid Build Coastguard Worker }
278*3ac0a46fSAndroid Build Coastguard Worker 
OutputMD5Hash(const char * file_name,pdfium::span<const uint8_t> output)279*3ac0a46fSAndroid Build Coastguard Worker void OutputMD5Hash(const char* file_name, pdfium::span<const uint8_t> output) {
280*3ac0a46fSAndroid Build Coastguard Worker   // Get the MD5 hash and write it to stdout.
281*3ac0a46fSAndroid Build Coastguard Worker   std::string hash = GenerateMD5Base16(output);
282*3ac0a46fSAndroid Build Coastguard Worker   printf("MD5:%s:%s\n", file_name, hash.c_str());
283*3ac0a46fSAndroid Build Coastguard Worker }
284*3ac0a46fSAndroid Build Coastguard Worker 
285*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_V8
286*3ac0a46fSAndroid Build Coastguard Worker 
287*3ac0a46fSAndroid Build Coastguard Worker struct V8IsolateDeleter {
operator ()__anon82c7a3370111::V8IsolateDeleter288*3ac0a46fSAndroid Build Coastguard Worker   inline void operator()(v8::Isolate* ptr) { ptr->Dispose(); }
289*3ac0a46fSAndroid Build Coastguard Worker };
290*3ac0a46fSAndroid Build Coastguard Worker 
291*3ac0a46fSAndroid Build Coastguard Worker // These example JS platform callback handlers are entirely optional,
292*3ac0a46fSAndroid Build Coastguard Worker // and exist here to show the flow of information from a document back
293*3ac0a46fSAndroid Build Coastguard Worker // to the embedder.
ExampleAppAlert(IPDF_JSPLATFORM *,FPDF_WIDESTRING msg,FPDF_WIDESTRING title,int type,int icon)294*3ac0a46fSAndroid Build Coastguard Worker int ExampleAppAlert(IPDF_JSPLATFORM*,
295*3ac0a46fSAndroid Build Coastguard Worker                     FPDF_WIDESTRING msg,
296*3ac0a46fSAndroid Build Coastguard Worker                     FPDF_WIDESTRING title,
297*3ac0a46fSAndroid Build Coastguard Worker                     int type,
298*3ac0a46fSAndroid Build Coastguard Worker                     int icon) {
299*3ac0a46fSAndroid Build Coastguard Worker   printf("%ls", GetPlatformWString(title).c_str());
300*3ac0a46fSAndroid Build Coastguard Worker   if (icon || type)
301*3ac0a46fSAndroid Build Coastguard Worker     printf("[icon=%d,type=%d]", icon, type);
302*3ac0a46fSAndroid Build Coastguard Worker   printf(": %ls\n", GetPlatformWString(msg).c_str());
303*3ac0a46fSAndroid Build Coastguard Worker   return 0;
304*3ac0a46fSAndroid Build Coastguard Worker }
305*3ac0a46fSAndroid Build Coastguard Worker 
ExampleAppBeep(IPDF_JSPLATFORM *,int type)306*3ac0a46fSAndroid Build Coastguard Worker void ExampleAppBeep(IPDF_JSPLATFORM*, int type) {
307*3ac0a46fSAndroid Build Coastguard Worker   printf("BEEP!!! %d\n", type);
308*3ac0a46fSAndroid Build Coastguard Worker }
309*3ac0a46fSAndroid Build Coastguard Worker 
ExampleAppResponse(IPDF_JSPLATFORM *,FPDF_WIDESTRING question,FPDF_WIDESTRING title,FPDF_WIDESTRING default_value,FPDF_WIDESTRING label,FPDF_BOOL is_password,void * response,int length)310*3ac0a46fSAndroid Build Coastguard Worker int ExampleAppResponse(IPDF_JSPLATFORM*,
311*3ac0a46fSAndroid Build Coastguard Worker                        FPDF_WIDESTRING question,
312*3ac0a46fSAndroid Build Coastguard Worker                        FPDF_WIDESTRING title,
313*3ac0a46fSAndroid Build Coastguard Worker                        FPDF_WIDESTRING default_value,
314*3ac0a46fSAndroid Build Coastguard Worker                        FPDF_WIDESTRING label,
315*3ac0a46fSAndroid Build Coastguard Worker                        FPDF_BOOL is_password,
316*3ac0a46fSAndroid Build Coastguard Worker                        void* response,
317*3ac0a46fSAndroid Build Coastguard Worker                        int length) {
318*3ac0a46fSAndroid Build Coastguard Worker   printf("%ls: %ls, defaultValue=%ls, label=%ls, isPassword=%d, length=%d\n",
319*3ac0a46fSAndroid Build Coastguard Worker          GetPlatformWString(title).c_str(),
320*3ac0a46fSAndroid Build Coastguard Worker          GetPlatformWString(question).c_str(),
321*3ac0a46fSAndroid Build Coastguard Worker          GetPlatformWString(default_value).c_str(),
322*3ac0a46fSAndroid Build Coastguard Worker          GetPlatformWString(label).c_str(), is_password, length);
323*3ac0a46fSAndroid Build Coastguard Worker 
324*3ac0a46fSAndroid Build Coastguard Worker   // UTF-16, always LE regardless of platform.
325*3ac0a46fSAndroid Build Coastguard Worker   auto* ptr = static_cast<uint8_t*>(response);
326*3ac0a46fSAndroid Build Coastguard Worker   ptr[0] = 'N';
327*3ac0a46fSAndroid Build Coastguard Worker   ptr[1] = 0;
328*3ac0a46fSAndroid Build Coastguard Worker   ptr[2] = 'o';
329*3ac0a46fSAndroid Build Coastguard Worker   ptr[3] = 0;
330*3ac0a46fSAndroid Build Coastguard Worker   return 4;
331*3ac0a46fSAndroid Build Coastguard Worker }
332*3ac0a46fSAndroid Build Coastguard Worker 
ExampleDocGetFilePath(IPDF_JSPLATFORM *,void * file_path,int length)333*3ac0a46fSAndroid Build Coastguard Worker int ExampleDocGetFilePath(IPDF_JSPLATFORM*, void* file_path, int length) {
334*3ac0a46fSAndroid Build Coastguard Worker   static const char kPath[] = "myfile.pdf";
335*3ac0a46fSAndroid Build Coastguard Worker   constexpr int kRequired = static_cast<int>(sizeof(kPath));
336*3ac0a46fSAndroid Build Coastguard Worker   if (file_path && length >= kRequired)
337*3ac0a46fSAndroid Build Coastguard Worker     memcpy(file_path, kPath, kRequired);
338*3ac0a46fSAndroid Build Coastguard Worker   return kRequired;
339*3ac0a46fSAndroid Build Coastguard Worker }
340*3ac0a46fSAndroid Build Coastguard Worker 
ExampleDocMail(IPDF_JSPLATFORM *,void * mailData,int length,FPDF_BOOL UI,FPDF_WIDESTRING To,FPDF_WIDESTRING Subject,FPDF_WIDESTRING CC,FPDF_WIDESTRING BCC,FPDF_WIDESTRING Msg)341*3ac0a46fSAndroid Build Coastguard Worker void ExampleDocMail(IPDF_JSPLATFORM*,
342*3ac0a46fSAndroid Build Coastguard Worker                     void* mailData,
343*3ac0a46fSAndroid Build Coastguard Worker                     int length,
344*3ac0a46fSAndroid Build Coastguard Worker                     FPDF_BOOL UI,
345*3ac0a46fSAndroid Build Coastguard Worker                     FPDF_WIDESTRING To,
346*3ac0a46fSAndroid Build Coastguard Worker                     FPDF_WIDESTRING Subject,
347*3ac0a46fSAndroid Build Coastguard Worker                     FPDF_WIDESTRING CC,
348*3ac0a46fSAndroid Build Coastguard Worker                     FPDF_WIDESTRING BCC,
349*3ac0a46fSAndroid Build Coastguard Worker                     FPDF_WIDESTRING Msg) {
350*3ac0a46fSAndroid Build Coastguard Worker   printf("Mail Msg: %d, to=%ls, cc=%ls, bcc=%ls, subject=%ls, body=%ls\n", UI,
351*3ac0a46fSAndroid Build Coastguard Worker          GetPlatformWString(To).c_str(), GetPlatformWString(CC).c_str(),
352*3ac0a46fSAndroid Build Coastguard Worker          GetPlatformWString(BCC).c_str(), GetPlatformWString(Subject).c_str(),
353*3ac0a46fSAndroid Build Coastguard Worker          GetPlatformWString(Msg).c_str());
354*3ac0a46fSAndroid Build Coastguard Worker }
355*3ac0a46fSAndroid Build Coastguard Worker 
ExampleDocPrint(IPDF_JSPLATFORM *,FPDF_BOOL bUI,int nStart,int nEnd,FPDF_BOOL bSilent,FPDF_BOOL bShrinkToFit,FPDF_BOOL bPrintAsImage,FPDF_BOOL bReverse,FPDF_BOOL bAnnotations)356*3ac0a46fSAndroid Build Coastguard Worker void ExampleDocPrint(IPDF_JSPLATFORM*,
357*3ac0a46fSAndroid Build Coastguard Worker                      FPDF_BOOL bUI,
358*3ac0a46fSAndroid Build Coastguard Worker                      int nStart,
359*3ac0a46fSAndroid Build Coastguard Worker                      int nEnd,
360*3ac0a46fSAndroid Build Coastguard Worker                      FPDF_BOOL bSilent,
361*3ac0a46fSAndroid Build Coastguard Worker                      FPDF_BOOL bShrinkToFit,
362*3ac0a46fSAndroid Build Coastguard Worker                      FPDF_BOOL bPrintAsImage,
363*3ac0a46fSAndroid Build Coastguard Worker                      FPDF_BOOL bReverse,
364*3ac0a46fSAndroid Build Coastguard Worker                      FPDF_BOOL bAnnotations) {
365*3ac0a46fSAndroid Build Coastguard Worker   printf("Doc Print: %d, %d, %d, %d, %d, %d, %d, %d\n", bUI, nStart, nEnd,
366*3ac0a46fSAndroid Build Coastguard Worker          bSilent, bShrinkToFit, bPrintAsImage, bReverse, bAnnotations);
367*3ac0a46fSAndroid Build Coastguard Worker }
368*3ac0a46fSAndroid Build Coastguard Worker 
ExampleDocSubmitForm(IPDF_JSPLATFORM *,void * formData,int length,FPDF_WIDESTRING url)369*3ac0a46fSAndroid Build Coastguard Worker void ExampleDocSubmitForm(IPDF_JSPLATFORM*,
370*3ac0a46fSAndroid Build Coastguard Worker                           void* formData,
371*3ac0a46fSAndroid Build Coastguard Worker                           int length,
372*3ac0a46fSAndroid Build Coastguard Worker                           FPDF_WIDESTRING url) {
373*3ac0a46fSAndroid Build Coastguard Worker   printf("Doc Submit Form: url=%ls + %d data bytes:\n",
374*3ac0a46fSAndroid Build Coastguard Worker          GetPlatformWString(url).c_str(), length);
375*3ac0a46fSAndroid Build Coastguard Worker   uint8_t* ptr = reinterpret_cast<uint8_t*>(formData);
376*3ac0a46fSAndroid Build Coastguard Worker   for (int i = 0; i < length; ++i)
377*3ac0a46fSAndroid Build Coastguard Worker     printf(" %02x", ptr[i]);
378*3ac0a46fSAndroid Build Coastguard Worker   printf("\n");
379*3ac0a46fSAndroid Build Coastguard Worker }
380*3ac0a46fSAndroid Build Coastguard Worker 
ExampleDocGotoPage(IPDF_JSPLATFORM *,int page_number)381*3ac0a46fSAndroid Build Coastguard Worker void ExampleDocGotoPage(IPDF_JSPLATFORM*, int page_number) {
382*3ac0a46fSAndroid Build Coastguard Worker   printf("Goto Page: %d\n", page_number);
383*3ac0a46fSAndroid Build Coastguard Worker }
384*3ac0a46fSAndroid Build Coastguard Worker 
ExampleFieldBrowse(IPDF_JSPLATFORM *,void * file_path,int length)385*3ac0a46fSAndroid Build Coastguard Worker int ExampleFieldBrowse(IPDF_JSPLATFORM*, void* file_path, int length) {
386*3ac0a46fSAndroid Build Coastguard Worker   static const char kPath[] = "selected.txt";
387*3ac0a46fSAndroid Build Coastguard Worker   constexpr int kRequired = static_cast<int>(sizeof(kPath));
388*3ac0a46fSAndroid Build Coastguard Worker   if (file_path && length >= kRequired)
389*3ac0a46fSAndroid Build Coastguard Worker     memcpy(file_path, kPath, kRequired);
390*3ac0a46fSAndroid Build Coastguard Worker   return kRequired;
391*3ac0a46fSAndroid Build Coastguard Worker }
392*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_V8
393*3ac0a46fSAndroid Build Coastguard Worker 
394*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_XFA
ExamplePopupMenu(FPDF_FORMFILLINFO * pInfo,FPDF_PAGE page,FPDF_WIDGET always_null,int flags,float x,float y)395*3ac0a46fSAndroid Build Coastguard Worker FPDF_BOOL ExamplePopupMenu(FPDF_FORMFILLINFO* pInfo,
396*3ac0a46fSAndroid Build Coastguard Worker                            FPDF_PAGE page,
397*3ac0a46fSAndroid Build Coastguard Worker                            FPDF_WIDGET always_null,
398*3ac0a46fSAndroid Build Coastguard Worker                            int flags,
399*3ac0a46fSAndroid Build Coastguard Worker                            float x,
400*3ac0a46fSAndroid Build Coastguard Worker                            float y) {
401*3ac0a46fSAndroid Build Coastguard Worker   printf("Popup: x=%2.1f, y=%2.1f, flags=0x%x\n", x, y, flags);
402*3ac0a46fSAndroid Build Coastguard Worker   return true;
403*3ac0a46fSAndroid Build Coastguard Worker }
404*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_XFA
405*3ac0a46fSAndroid Build Coastguard Worker 
ExampleNamedAction(FPDF_FORMFILLINFO * pInfo,FPDF_BYTESTRING name)406*3ac0a46fSAndroid Build Coastguard Worker void ExampleNamedAction(FPDF_FORMFILLINFO* pInfo, FPDF_BYTESTRING name) {
407*3ac0a46fSAndroid Build Coastguard Worker   printf("Execute named action: %s\n", name);
408*3ac0a46fSAndroid Build Coastguard Worker }
409*3ac0a46fSAndroid Build Coastguard Worker 
ExampleUnsupportedHandler(UNSUPPORT_INFO *,int type)410*3ac0a46fSAndroid Build Coastguard Worker void ExampleUnsupportedHandler(UNSUPPORT_INFO*, int type) {
411*3ac0a46fSAndroid Build Coastguard Worker   std::string feature = "Unknown";
412*3ac0a46fSAndroid Build Coastguard Worker   switch (type) {
413*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_UNSP_DOC_XFAFORM:
414*3ac0a46fSAndroid Build Coastguard Worker       feature = "XFA";
415*3ac0a46fSAndroid Build Coastguard Worker       break;
416*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_UNSP_DOC_PORTABLECOLLECTION:
417*3ac0a46fSAndroid Build Coastguard Worker       feature = "Portfolios_Packages";
418*3ac0a46fSAndroid Build Coastguard Worker       break;
419*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_UNSP_DOC_ATTACHMENT:
420*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_UNSP_ANNOT_ATTACHMENT:
421*3ac0a46fSAndroid Build Coastguard Worker       feature = "Attachment";
422*3ac0a46fSAndroid Build Coastguard Worker       break;
423*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_UNSP_DOC_SECURITY:
424*3ac0a46fSAndroid Build Coastguard Worker       feature = "Rights_Management";
425*3ac0a46fSAndroid Build Coastguard Worker       break;
426*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_UNSP_DOC_SHAREDREVIEW:
427*3ac0a46fSAndroid Build Coastguard Worker       feature = "Shared_Review";
428*3ac0a46fSAndroid Build Coastguard Worker       break;
429*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_UNSP_DOC_SHAREDFORM_ACROBAT:
430*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM:
431*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_UNSP_DOC_SHAREDFORM_EMAIL:
432*3ac0a46fSAndroid Build Coastguard Worker       feature = "Shared_Form";
433*3ac0a46fSAndroid Build Coastguard Worker       break;
434*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_UNSP_ANNOT_3DANNOT:
435*3ac0a46fSAndroid Build Coastguard Worker       feature = "3D";
436*3ac0a46fSAndroid Build Coastguard Worker       break;
437*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_UNSP_ANNOT_MOVIE:
438*3ac0a46fSAndroid Build Coastguard Worker       feature = "Movie";
439*3ac0a46fSAndroid Build Coastguard Worker       break;
440*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_UNSP_ANNOT_SOUND:
441*3ac0a46fSAndroid Build Coastguard Worker       feature = "Sound";
442*3ac0a46fSAndroid Build Coastguard Worker       break;
443*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_UNSP_ANNOT_SCREEN_MEDIA:
444*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA:
445*3ac0a46fSAndroid Build Coastguard Worker       feature = "Screen";
446*3ac0a46fSAndroid Build Coastguard Worker       break;
447*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_UNSP_ANNOT_SIG:
448*3ac0a46fSAndroid Build Coastguard Worker       feature = "Digital_Signature";
449*3ac0a46fSAndroid Build Coastguard Worker       break;
450*3ac0a46fSAndroid Build Coastguard Worker   }
451*3ac0a46fSAndroid Build Coastguard Worker   printf("Unsupported feature: %s.\n", feature.c_str());
452*3ac0a46fSAndroid Build Coastguard Worker }
453*3ac0a46fSAndroid Build Coastguard Worker 
ParseCommandLine(const std::vector<std::string> & args,Options * options,std::vector<std::string> * files)454*3ac0a46fSAndroid Build Coastguard Worker bool ParseCommandLine(const std::vector<std::string>& args,
455*3ac0a46fSAndroid Build Coastguard Worker                       Options* options,
456*3ac0a46fSAndroid Build Coastguard Worker                       std::vector<std::string>* files) {
457*3ac0a46fSAndroid Build Coastguard Worker   if (args.empty())
458*3ac0a46fSAndroid Build Coastguard Worker     return false;
459*3ac0a46fSAndroid Build Coastguard Worker 
460*3ac0a46fSAndroid Build Coastguard Worker   options->exe_path = args[0];
461*3ac0a46fSAndroid Build Coastguard Worker   size_t cur_idx = 1;
462*3ac0a46fSAndroid Build Coastguard Worker   std::string value;
463*3ac0a46fSAndroid Build Coastguard Worker   for (; cur_idx < args.size(); ++cur_idx) {
464*3ac0a46fSAndroid Build Coastguard Worker     const std::string& cur_arg = args[cur_idx];
465*3ac0a46fSAndroid Build Coastguard Worker     if (cur_arg == "--show-config") {
466*3ac0a46fSAndroid Build Coastguard Worker       options->show_config = true;
467*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--show-metadata") {
468*3ac0a46fSAndroid Build Coastguard Worker       options->show_metadata = true;
469*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--send-events") {
470*3ac0a46fSAndroid Build Coastguard Worker       options->send_events = true;
471*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--mem-document") {
472*3ac0a46fSAndroid Build Coastguard Worker       options->use_load_mem_document = true;
473*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--render-oneshot") {
474*3ac0a46fSAndroid Build Coastguard Worker       options->render_oneshot = true;
475*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--lcd-text") {
476*3ac0a46fSAndroid Build Coastguard Worker       options->lcd_text = true;
477*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--no-nativetext") {
478*3ac0a46fSAndroid Build Coastguard Worker       options->no_nativetext = true;
479*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--grayscale") {
480*3ac0a46fSAndroid Build Coastguard Worker       options->grayscale = true;
481*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--forced-color") {
482*3ac0a46fSAndroid Build Coastguard Worker       options->forced_color = true;
483*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--fill-to-stroke") {
484*3ac0a46fSAndroid Build Coastguard Worker       options->fill_to_stroke = true;
485*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--limit-cache") {
486*3ac0a46fSAndroid Build Coastguard Worker       options->limit_cache = true;
487*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--force-halftone") {
488*3ac0a46fSAndroid Build Coastguard Worker       options->force_halftone = true;
489*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--printing") {
490*3ac0a46fSAndroid Build Coastguard Worker       options->printing = true;
491*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--no-smoothtext") {
492*3ac0a46fSAndroid Build Coastguard Worker       options->no_smoothtext = true;
493*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--no-smoothimage") {
494*3ac0a46fSAndroid Build Coastguard Worker       options->no_smoothimage = true;
495*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--no-smoothpath") {
496*3ac0a46fSAndroid Build Coastguard Worker       options->no_smoothpath = true;
497*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--reverse-byte-order") {
498*3ac0a46fSAndroid Build Coastguard Worker       options->reverse_byte_order = true;
499*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--save-attachments") {
500*3ac0a46fSAndroid Build Coastguard Worker       options->save_attachments = true;
501*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--save-images") {
502*3ac0a46fSAndroid Build Coastguard Worker       if (options->save_rendered_images) {
503*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr,
504*3ac0a46fSAndroid Build Coastguard Worker                 "--save-rendered-images conflicts with --save-images\n");
505*3ac0a46fSAndroid Build Coastguard Worker         return false;
506*3ac0a46fSAndroid Build Coastguard Worker       }
507*3ac0a46fSAndroid Build Coastguard Worker       options->save_images = true;
508*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--save-rendered-images") {
509*3ac0a46fSAndroid Build Coastguard Worker       if (options->save_images) {
510*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr,
511*3ac0a46fSAndroid Build Coastguard Worker                 "--save-images conflicts with --save-rendered-images\n");
512*3ac0a46fSAndroid Build Coastguard Worker         return false;
513*3ac0a46fSAndroid Build Coastguard Worker       }
514*3ac0a46fSAndroid Build Coastguard Worker       options->save_rendered_images = true;
515*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--save-thumbs") {
516*3ac0a46fSAndroid Build Coastguard Worker       options->save_thumbnails = true;
517*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--save-thumbs-dec") {
518*3ac0a46fSAndroid Build Coastguard Worker       options->save_thumbnails_decoded = true;
519*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--save-thumbs-raw") {
520*3ac0a46fSAndroid Build Coastguard Worker       options->save_thumbnails_raw = true;
521*3ac0a46fSAndroid Build Coastguard Worker     } else if (ParseSwitchKeyValue(cur_arg, "--use-renderer=", &value)) {
522*3ac0a46fSAndroid Build Coastguard Worker       if (options->use_renderer_type != RendererType::kDefault) {
523*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate --use-renderer argument\n");
524*3ac0a46fSAndroid Build Coastguard Worker         return false;
525*3ac0a46fSAndroid Build Coastguard Worker       }
526*3ac0a46fSAndroid Build Coastguard Worker       if (value == "agg") {
527*3ac0a46fSAndroid Build Coastguard Worker         options->use_renderer_type = RendererType::kAgg;
528*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
529*3ac0a46fSAndroid Build Coastguard Worker       } else if (value == "gdi") {
530*3ac0a46fSAndroid Build Coastguard Worker         options->use_renderer_type = RendererType::kGdi;
531*3ac0a46fSAndroid Build Coastguard Worker #endif  // _WIN32
532*3ac0a46fSAndroid Build Coastguard Worker #if defined(PDF_ENABLE_SKIA)
533*3ac0a46fSAndroid Build Coastguard Worker       } else if (value == "skia") {
534*3ac0a46fSAndroid Build Coastguard Worker         options->use_renderer_type = RendererType::kSkia;
535*3ac0a46fSAndroid Build Coastguard Worker #endif  // defined(PDF_ENABLE_SKIA)
536*3ac0a46fSAndroid Build Coastguard Worker       } else {
537*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Invalid --use-renderer argument\n");
538*3ac0a46fSAndroid Build Coastguard Worker         return false;
539*3ac0a46fSAndroid Build Coastguard Worker       }
540*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_V8
541*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--disable-javascript") {
542*3ac0a46fSAndroid Build Coastguard Worker       options->disable_javascript = true;
543*3ac0a46fSAndroid Build Coastguard Worker     } else if (ParseSwitchKeyValue(cur_arg, "--js-flags=", &value)) {
544*3ac0a46fSAndroid Build Coastguard Worker       if (!options->js_flags.empty()) {
545*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate --js-flags argument\n");
546*3ac0a46fSAndroid Build Coastguard Worker         return false;
547*3ac0a46fSAndroid Build Coastguard Worker       }
548*3ac0a46fSAndroid Build Coastguard Worker       options->js_flags = value;
549*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_XFA
550*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--disable-xfa") {
551*3ac0a46fSAndroid Build Coastguard Worker       options->disable_xfa = true;
552*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_XFA
553*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_V8
554*3ac0a46fSAndroid Build Coastguard Worker #ifdef ENABLE_CALLGRIND
555*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--callgrind-delim") {
556*3ac0a46fSAndroid Build Coastguard Worker       options->callgrind_delimiters = true;
557*3ac0a46fSAndroid Build Coastguard Worker #endif
558*3ac0a46fSAndroid Build Coastguard Worker #if defined(__APPLE__) || (defined(__linux__) && !defined(__ANDROID__))
559*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--no-system-fonts") {
560*3ac0a46fSAndroid Build Coastguard Worker       options->linux_no_system_fonts = true;
561*3ac0a46fSAndroid Build Coastguard Worker #endif
562*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--croscore-font-names") {
563*3ac0a46fSAndroid Build Coastguard Worker       options->croscore_font_names = true;
564*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--ppm") {
565*3ac0a46fSAndroid Build Coastguard Worker       if (options->output_format != OutputFormat::kNone) {
566*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate or conflicting --ppm argument\n");
567*3ac0a46fSAndroid Build Coastguard Worker         return false;
568*3ac0a46fSAndroid Build Coastguard Worker       }
569*3ac0a46fSAndroid Build Coastguard Worker       options->output_format = OutputFormat::kPpm;
570*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--png") {
571*3ac0a46fSAndroid Build Coastguard Worker       if (options->output_format != OutputFormat::kNone) {
572*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate or conflicting --png argument\n");
573*3ac0a46fSAndroid Build Coastguard Worker         return false;
574*3ac0a46fSAndroid Build Coastguard Worker       }
575*3ac0a46fSAndroid Build Coastguard Worker       options->output_format = OutputFormat::kPng;
576*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--txt") {
577*3ac0a46fSAndroid Build Coastguard Worker       if (options->output_format != OutputFormat::kNone) {
578*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate or conflicting --txt argument\n");
579*3ac0a46fSAndroid Build Coastguard Worker         return false;
580*3ac0a46fSAndroid Build Coastguard Worker       }
581*3ac0a46fSAndroid Build Coastguard Worker       options->output_format = OutputFormat::kText;
582*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--annot") {
583*3ac0a46fSAndroid Build Coastguard Worker       if (options->output_format != OutputFormat::kNone) {
584*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate or conflicting --annot argument\n");
585*3ac0a46fSAndroid Build Coastguard Worker         return false;
586*3ac0a46fSAndroid Build Coastguard Worker       }
587*3ac0a46fSAndroid Build Coastguard Worker       options->output_format = OutputFormat::kAnnot;
588*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_SKIA
589*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--skp") {
590*3ac0a46fSAndroid Build Coastguard Worker       if (options->output_format != OutputFormat::kNone) {
591*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate or conflicting --skp argument\n");
592*3ac0a46fSAndroid Build Coastguard Worker         return false;
593*3ac0a46fSAndroid Build Coastguard Worker       }
594*3ac0a46fSAndroid Build Coastguard Worker       options->output_format = OutputFormat::kSkp;
595*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
596*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--xps") {
597*3ac0a46fSAndroid Build Coastguard Worker       if (options->output_format != OutputFormat::kNone) {
598*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate or conflicting --xps argument\n");
599*3ac0a46fSAndroid Build Coastguard Worker         return false;
600*3ac0a46fSAndroid Build Coastguard Worker       }
601*3ac0a46fSAndroid Build Coastguard Worker       options->output_format = OutputFormat::kXps;
602*3ac0a46fSAndroid Build Coastguard Worker #endif  // _WIN32
603*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_SKIA
604*3ac0a46fSAndroid Build Coastguard Worker     } else if (ParseSwitchKeyValue(cur_arg, "--font-dir=", &value)) {
605*3ac0a46fSAndroid Build Coastguard Worker       if (!options->font_directory.empty()) {
606*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate --font-dir argument\n");
607*3ac0a46fSAndroid Build Coastguard Worker         return false;
608*3ac0a46fSAndroid Build Coastguard Worker       }
609*3ac0a46fSAndroid Build Coastguard Worker       std::string path = value;
610*3ac0a46fSAndroid Build Coastguard Worker       absl::optional<std::string> expanded_path = ExpandDirectoryPath(path);
611*3ac0a46fSAndroid Build Coastguard Worker       if (!expanded_path.has_value()) {
612*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Failed to expand --font-dir, %s\n", path.c_str());
613*3ac0a46fSAndroid Build Coastguard Worker         return false;
614*3ac0a46fSAndroid Build Coastguard Worker       }
615*3ac0a46fSAndroid Build Coastguard Worker 
616*3ac0a46fSAndroid Build Coastguard Worker       if (!PathService::DirectoryExists(expanded_path.value())) {
617*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "--font-dir, %s, appears to not be a directory\n",
618*3ac0a46fSAndroid Build Coastguard Worker                 path.c_str());
619*3ac0a46fSAndroid Build Coastguard Worker         return false;
620*3ac0a46fSAndroid Build Coastguard Worker       }
621*3ac0a46fSAndroid Build Coastguard Worker 
622*3ac0a46fSAndroid Build Coastguard Worker       options->font_directory = expanded_path.value();
623*3ac0a46fSAndroid Build Coastguard Worker 
624*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
625*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--emf") {
626*3ac0a46fSAndroid Build Coastguard Worker       if (options->output_format != OutputFormat::kNone) {
627*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate or conflicting --emf argument\n");
628*3ac0a46fSAndroid Build Coastguard Worker         return false;
629*3ac0a46fSAndroid Build Coastguard Worker       }
630*3ac0a46fSAndroid Build Coastguard Worker       options->output_format = OutputFormat::kEmf;
631*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--ps2") {
632*3ac0a46fSAndroid Build Coastguard Worker       if (options->output_format != OutputFormat::kNone) {
633*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate or conflicting --ps2 argument\n");
634*3ac0a46fSAndroid Build Coastguard Worker         return false;
635*3ac0a46fSAndroid Build Coastguard Worker       }
636*3ac0a46fSAndroid Build Coastguard Worker       options->output_format = OutputFormat::kPs2;
637*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--ps3") {
638*3ac0a46fSAndroid Build Coastguard Worker       if (options->output_format != OutputFormat::kNone) {
639*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate or conflicting --ps3 argument\n");
640*3ac0a46fSAndroid Build Coastguard Worker         return false;
641*3ac0a46fSAndroid Build Coastguard Worker       }
642*3ac0a46fSAndroid Build Coastguard Worker       options->output_format = OutputFormat::kPs3;
643*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--ps3-type42") {
644*3ac0a46fSAndroid Build Coastguard Worker       if (options->output_format != OutputFormat::kNone) {
645*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate or conflicting --ps3-type42 argument\n");
646*3ac0a46fSAndroid Build Coastguard Worker         return false;
647*3ac0a46fSAndroid Build Coastguard Worker       }
648*3ac0a46fSAndroid Build Coastguard Worker       options->output_format = OutputFormat::kPs3Type42;
649*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--bmp") {
650*3ac0a46fSAndroid Build Coastguard Worker       if (options->output_format != OutputFormat::kNone) {
651*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate or conflicting --bmp argument\n");
652*3ac0a46fSAndroid Build Coastguard Worker         return false;
653*3ac0a46fSAndroid Build Coastguard Worker       }
654*3ac0a46fSAndroid Build Coastguard Worker       options->output_format = OutputFormat::kBmp;
655*3ac0a46fSAndroid Build Coastguard Worker #endif  // _WIN32
656*3ac0a46fSAndroid Build Coastguard Worker 
657*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_V8
658*3ac0a46fSAndroid Build Coastguard Worker #ifdef V8_USE_EXTERNAL_STARTUP_DATA
659*3ac0a46fSAndroid Build Coastguard Worker     } else if (ParseSwitchKeyValue(cur_arg, "--bin-dir=", &value)) {
660*3ac0a46fSAndroid Build Coastguard Worker       if (!options->bin_directory.empty()) {
661*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate --bin-dir argument\n");
662*3ac0a46fSAndroid Build Coastguard Worker         return false;
663*3ac0a46fSAndroid Build Coastguard Worker       }
664*3ac0a46fSAndroid Build Coastguard Worker       std::string path = value;
665*3ac0a46fSAndroid Build Coastguard Worker       absl::optional<std::string> expanded_path = ExpandDirectoryPath(path);
666*3ac0a46fSAndroid Build Coastguard Worker       if (!expanded_path.has_value()) {
667*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Failed to expand --bin-dir, %s\n", path.c_str());
668*3ac0a46fSAndroid Build Coastguard Worker         return false;
669*3ac0a46fSAndroid Build Coastguard Worker       }
670*3ac0a46fSAndroid Build Coastguard Worker       options->bin_directory = expanded_path.value();
671*3ac0a46fSAndroid Build Coastguard Worker #endif  // V8_USE_EXTERNAL_STARTUP_DATA
672*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_V8
673*3ac0a46fSAndroid Build Coastguard Worker 
674*3ac0a46fSAndroid Build Coastguard Worker     } else if (ParseSwitchKeyValue(cur_arg, "--password=", &value)) {
675*3ac0a46fSAndroid Build Coastguard Worker       if (!options->password.empty()) {
676*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate --password argument\n");
677*3ac0a46fSAndroid Build Coastguard Worker         return false;
678*3ac0a46fSAndroid Build Coastguard Worker       }
679*3ac0a46fSAndroid Build Coastguard Worker       options->password = value;
680*3ac0a46fSAndroid Build Coastguard Worker     } else if (ParseSwitchKeyValue(cur_arg, "--scale=", &value)) {
681*3ac0a46fSAndroid Build Coastguard Worker       if (!options->scale_factor_as_string.empty()) {
682*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate --scale argument\n");
683*3ac0a46fSAndroid Build Coastguard Worker         return false;
684*3ac0a46fSAndroid Build Coastguard Worker       }
685*3ac0a46fSAndroid Build Coastguard Worker       options->scale_factor_as_string = value;
686*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--show-pageinfo") {
687*3ac0a46fSAndroid Build Coastguard Worker       if (options->output_format != OutputFormat::kNone) {
688*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate or conflicting --show-pageinfo argument\n");
689*3ac0a46fSAndroid Build Coastguard Worker         return false;
690*3ac0a46fSAndroid Build Coastguard Worker       }
691*3ac0a46fSAndroid Build Coastguard Worker       options->output_format = OutputFormat::kPageInfo;
692*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--show-structure") {
693*3ac0a46fSAndroid Build Coastguard Worker       if (options->output_format != OutputFormat::kNone) {
694*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate or conflicting --show-structure argument\n");
695*3ac0a46fSAndroid Build Coastguard Worker         return false;
696*3ac0a46fSAndroid Build Coastguard Worker       }
697*3ac0a46fSAndroid Build Coastguard Worker       options->output_format = OutputFormat::kStructure;
698*3ac0a46fSAndroid Build Coastguard Worker     } else if (ParseSwitchKeyValue(cur_arg, "--pages=", &value)) {
699*3ac0a46fSAndroid Build Coastguard Worker       if (options->pages) {
700*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate --pages argument\n");
701*3ac0a46fSAndroid Build Coastguard Worker         return false;
702*3ac0a46fSAndroid Build Coastguard Worker       }
703*3ac0a46fSAndroid Build Coastguard Worker       options->pages = true;
704*3ac0a46fSAndroid Build Coastguard Worker       const std::string pages_string = value;
705*3ac0a46fSAndroid Build Coastguard Worker       size_t first_dash = pages_string.find('-');
706*3ac0a46fSAndroid Build Coastguard Worker       if (first_dash == std::string::npos) {
707*3ac0a46fSAndroid Build Coastguard Worker         std::stringstream(pages_string) >> options->first_page;
708*3ac0a46fSAndroid Build Coastguard Worker         options->last_page = options->first_page;
709*3ac0a46fSAndroid Build Coastguard Worker       } else {
710*3ac0a46fSAndroid Build Coastguard Worker         std::stringstream(pages_string.substr(0, first_dash)) >>
711*3ac0a46fSAndroid Build Coastguard Worker             options->first_page;
712*3ac0a46fSAndroid Build Coastguard Worker         std::stringstream(pages_string.substr(first_dash + 1)) >>
713*3ac0a46fSAndroid Build Coastguard Worker             options->last_page;
714*3ac0a46fSAndroid Build Coastguard Worker       }
715*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg == "--md5") {
716*3ac0a46fSAndroid Build Coastguard Worker       options->md5 = true;
717*3ac0a46fSAndroid Build Coastguard Worker     } else if (ParseSwitchKeyValue(cur_arg, "--time=", &value)) {
718*3ac0a46fSAndroid Build Coastguard Worker       if (options->time > -1) {
719*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Duplicate --time argument\n");
720*3ac0a46fSAndroid Build Coastguard Worker         return false;
721*3ac0a46fSAndroid Build Coastguard Worker       }
722*3ac0a46fSAndroid Build Coastguard Worker       const std::string time_string = value;
723*3ac0a46fSAndroid Build Coastguard Worker       std::stringstream(time_string) >> options->time;
724*3ac0a46fSAndroid Build Coastguard Worker       if (options->time < 0) {
725*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Invalid --time argument, must be non-negative\n");
726*3ac0a46fSAndroid Build Coastguard Worker         return false;
727*3ac0a46fSAndroid Build Coastguard Worker       }
728*3ac0a46fSAndroid Build Coastguard Worker     } else if (cur_arg.size() >= 2 && cur_arg[0] == '-' && cur_arg[1] == '-') {
729*3ac0a46fSAndroid Build Coastguard Worker       fprintf(stderr, "Unrecognized argument %s\n", cur_arg.c_str());
730*3ac0a46fSAndroid Build Coastguard Worker       return false;
731*3ac0a46fSAndroid Build Coastguard Worker     } else {
732*3ac0a46fSAndroid Build Coastguard Worker       break;
733*3ac0a46fSAndroid Build Coastguard Worker     }
734*3ac0a46fSAndroid Build Coastguard Worker   }
735*3ac0a46fSAndroid Build Coastguard Worker   for (size_t i = cur_idx; i < args.size(); i++)
736*3ac0a46fSAndroid Build Coastguard Worker     files->push_back(args[i]);
737*3ac0a46fSAndroid Build Coastguard Worker 
738*3ac0a46fSAndroid Build Coastguard Worker   return true;
739*3ac0a46fSAndroid Build Coastguard Worker }
740*3ac0a46fSAndroid Build Coastguard Worker 
PrintLastError()741*3ac0a46fSAndroid Build Coastguard Worker void PrintLastError() {
742*3ac0a46fSAndroid Build Coastguard Worker   unsigned long err = FPDF_GetLastError();
743*3ac0a46fSAndroid Build Coastguard Worker   fprintf(stderr, "Load pdf docs unsuccessful: ");
744*3ac0a46fSAndroid Build Coastguard Worker   switch (err) {
745*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_ERR_SUCCESS:
746*3ac0a46fSAndroid Build Coastguard Worker       fprintf(stderr, "Success");
747*3ac0a46fSAndroid Build Coastguard Worker       break;
748*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_ERR_UNKNOWN:
749*3ac0a46fSAndroid Build Coastguard Worker       fprintf(stderr, "Unknown error");
750*3ac0a46fSAndroid Build Coastguard Worker       break;
751*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_ERR_FILE:
752*3ac0a46fSAndroid Build Coastguard Worker       fprintf(stderr, "File not found or could not be opened");
753*3ac0a46fSAndroid Build Coastguard Worker       break;
754*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_ERR_FORMAT:
755*3ac0a46fSAndroid Build Coastguard Worker       fprintf(stderr, "File not in PDF format or corrupted");
756*3ac0a46fSAndroid Build Coastguard Worker       break;
757*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_ERR_PASSWORD:
758*3ac0a46fSAndroid Build Coastguard Worker       fprintf(stderr, "Password required or incorrect password");
759*3ac0a46fSAndroid Build Coastguard Worker       break;
760*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_ERR_SECURITY:
761*3ac0a46fSAndroid Build Coastguard Worker       fprintf(stderr, "Unsupported security scheme");
762*3ac0a46fSAndroid Build Coastguard Worker       break;
763*3ac0a46fSAndroid Build Coastguard Worker     case FPDF_ERR_PAGE:
764*3ac0a46fSAndroid Build Coastguard Worker       fprintf(stderr, "Page not found or content error");
765*3ac0a46fSAndroid Build Coastguard Worker       break;
766*3ac0a46fSAndroid Build Coastguard Worker     default:
767*3ac0a46fSAndroid Build Coastguard Worker       fprintf(stderr, "Unknown error %ld", err);
768*3ac0a46fSAndroid Build Coastguard Worker   }
769*3ac0a46fSAndroid Build Coastguard Worker   fprintf(stderr, ".\n");
770*3ac0a46fSAndroid Build Coastguard Worker }
771*3ac0a46fSAndroid Build Coastguard Worker 
Is_Data_Avail(FX_FILEAVAIL * avail,size_t offset,size_t size)772*3ac0a46fSAndroid Build Coastguard Worker FPDF_BOOL Is_Data_Avail(FX_FILEAVAIL* avail, size_t offset, size_t size) {
773*3ac0a46fSAndroid Build Coastguard Worker   return true;
774*3ac0a46fSAndroid Build Coastguard Worker }
775*3ac0a46fSAndroid Build Coastguard Worker 
Add_Segment(FX_DOWNLOADHINTS * hints,size_t offset,size_t size)776*3ac0a46fSAndroid Build Coastguard Worker void Add_Segment(FX_DOWNLOADHINTS* hints, size_t offset, size_t size) {}
777*3ac0a46fSAndroid Build Coastguard Worker 
GetPageForIndex(FPDF_FORMFILLINFO * param,FPDF_DOCUMENT doc,int index)778*3ac0a46fSAndroid Build Coastguard Worker FPDF_PAGE GetPageForIndex(FPDF_FORMFILLINFO* param,
779*3ac0a46fSAndroid Build Coastguard Worker                           FPDF_DOCUMENT doc,
780*3ac0a46fSAndroid Build Coastguard Worker                           int index) {
781*3ac0a46fSAndroid Build Coastguard Worker   FPDF_FORMFILLINFO_PDFiumTest* form_fill_info =
782*3ac0a46fSAndroid Build Coastguard Worker       ToPDFiumTestFormFillInfo(param);
783*3ac0a46fSAndroid Build Coastguard Worker   auto& loaded_pages = form_fill_info->loaded_pages;
784*3ac0a46fSAndroid Build Coastguard Worker   auto iter = loaded_pages.find(index);
785*3ac0a46fSAndroid Build Coastguard Worker   if (iter != loaded_pages.end())
786*3ac0a46fSAndroid Build Coastguard Worker     return iter->second.get();
787*3ac0a46fSAndroid Build Coastguard Worker 
788*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFPage page(FPDF_LoadPage(doc, index));
789*3ac0a46fSAndroid Build Coastguard Worker   if (!page)
790*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
791*3ac0a46fSAndroid Build Coastguard Worker 
792*3ac0a46fSAndroid Build Coastguard Worker   // Mark the page as loaded first to prevent infinite recursion.
793*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page_ptr = page.get();
794*3ac0a46fSAndroid Build Coastguard Worker   loaded_pages[index] = std::move(page);
795*3ac0a46fSAndroid Build Coastguard Worker 
796*3ac0a46fSAndroid Build Coastguard Worker   FPDF_FORMHANDLE& form_handle = form_fill_info->form_handle;
797*3ac0a46fSAndroid Build Coastguard Worker   FORM_OnAfterLoadPage(page_ptr, form_handle);
798*3ac0a46fSAndroid Build Coastguard Worker   FORM_DoPageAAction(page_ptr, form_handle, FPDFPAGE_AACTION_OPEN);
799*3ac0a46fSAndroid Build Coastguard Worker   return page_ptr;
800*3ac0a46fSAndroid Build Coastguard Worker }
801*3ac0a46fSAndroid Build Coastguard Worker 
802*3ac0a46fSAndroid Build Coastguard Worker // Note, for a client using progressive rendering you'd want to determine if you
803*3ac0a46fSAndroid Build Coastguard Worker // need the rendering to pause instead of always saying |true|. This is for
804*3ac0a46fSAndroid Build Coastguard Worker // testing to force the renderer to break whenever possible.
NeedToPauseNow(IFSDK_PAUSE * p)805*3ac0a46fSAndroid Build Coastguard Worker FPDF_BOOL NeedToPauseNow(IFSDK_PAUSE* p) {
806*3ac0a46fSAndroid Build Coastguard Worker   return true;
807*3ac0a46fSAndroid Build Coastguard Worker }
808*3ac0a46fSAndroid Build Coastguard Worker 
809*3ac0a46fSAndroid Build Coastguard Worker class Processor final {
810*3ac0a46fSAndroid Build Coastguard Worker  public:
Processor(const Options * options,const std::function<void ()> * idler)811*3ac0a46fSAndroid Build Coastguard Worker   Processor(const Options* options, const std::function<void()>* idler)
812*3ac0a46fSAndroid Build Coastguard Worker       : options_(options), idler_(idler) {
813*3ac0a46fSAndroid Build Coastguard Worker     DCHECK(options_);
814*3ac0a46fSAndroid Build Coastguard Worker     DCHECK(idler_);
815*3ac0a46fSAndroid Build Coastguard Worker   }
816*3ac0a46fSAndroid Build Coastguard Worker 
options() const817*3ac0a46fSAndroid Build Coastguard Worker   const Options& options() const { return *options_; }
idler() const818*3ac0a46fSAndroid Build Coastguard Worker   const std::function<void()>& idler() const { return *idler_; }
819*3ac0a46fSAndroid Build Coastguard Worker 
820*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
com_factory()821*3ac0a46fSAndroid Build Coastguard Worker   ComFactory& com_factory() { return com_factory_; }
822*3ac0a46fSAndroid Build Coastguard Worker #endif  // _WIN32
823*3ac0a46fSAndroid Build Coastguard Worker 
824*3ac0a46fSAndroid Build Coastguard Worker   // Invokes `idler()`.
Idle() const825*3ac0a46fSAndroid Build Coastguard Worker   void Idle() const { idler()(); }
826*3ac0a46fSAndroid Build Coastguard Worker 
827*3ac0a46fSAndroid Build Coastguard Worker   void ProcessPdf(const std::string& name,
828*3ac0a46fSAndroid Build Coastguard Worker                   const char* buf,
829*3ac0a46fSAndroid Build Coastguard Worker                   size_t len,
830*3ac0a46fSAndroid Build Coastguard Worker                   const std::string& events);
831*3ac0a46fSAndroid Build Coastguard Worker 
832*3ac0a46fSAndroid Build Coastguard Worker  private:
833*3ac0a46fSAndroid Build Coastguard Worker   const Options* options_;
834*3ac0a46fSAndroid Build Coastguard Worker   const std::function<void()>* idler_;
835*3ac0a46fSAndroid Build Coastguard Worker 
836*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
837*3ac0a46fSAndroid Build Coastguard Worker   ComFactory com_factory_;
838*3ac0a46fSAndroid Build Coastguard Worker #endif  // _WIN32
839*3ac0a46fSAndroid Build Coastguard Worker };
840*3ac0a46fSAndroid Build Coastguard Worker 
841*3ac0a46fSAndroid Build Coastguard Worker class PdfProcessor final {
842*3ac0a46fSAndroid Build Coastguard Worker  public:
PdfProcessor(Processor * processor,const std::string * name,const std::string * events,FPDF_DOCUMENT doc,FPDF_FORMHANDLE form,FPDF_FORMFILLINFO_PDFiumTest * form_fill_info)843*3ac0a46fSAndroid Build Coastguard Worker   PdfProcessor(Processor* processor,
844*3ac0a46fSAndroid Build Coastguard Worker                const std::string* name,
845*3ac0a46fSAndroid Build Coastguard Worker                const std::string* events,
846*3ac0a46fSAndroid Build Coastguard Worker                FPDF_DOCUMENT doc,
847*3ac0a46fSAndroid Build Coastguard Worker                FPDF_FORMHANDLE form,
848*3ac0a46fSAndroid Build Coastguard Worker                FPDF_FORMFILLINFO_PDFiumTest* form_fill_info)
849*3ac0a46fSAndroid Build Coastguard Worker       : processor_(processor),
850*3ac0a46fSAndroid Build Coastguard Worker         name_(name),
851*3ac0a46fSAndroid Build Coastguard Worker         events_(events),
852*3ac0a46fSAndroid Build Coastguard Worker         doc_(doc),
853*3ac0a46fSAndroid Build Coastguard Worker         form_(form),
854*3ac0a46fSAndroid Build Coastguard Worker         form_fill_info_(form_fill_info) {
855*3ac0a46fSAndroid Build Coastguard Worker     DCHECK(processor_);
856*3ac0a46fSAndroid Build Coastguard Worker     DCHECK(name_);
857*3ac0a46fSAndroid Build Coastguard Worker     DCHECK(events_);
858*3ac0a46fSAndroid Build Coastguard Worker     DCHECK(doc_);
859*3ac0a46fSAndroid Build Coastguard Worker     DCHECK(form_);
860*3ac0a46fSAndroid Build Coastguard Worker     DCHECK(form_fill_info_);
861*3ac0a46fSAndroid Build Coastguard Worker   }
862*3ac0a46fSAndroid Build Coastguard Worker 
863*3ac0a46fSAndroid Build Coastguard Worker   bool ProcessPage(int page_index);
864*3ac0a46fSAndroid Build Coastguard Worker 
865*3ac0a46fSAndroid Build Coastguard Worker  private:
866*3ac0a46fSAndroid Build Coastguard Worker   // Per processor state.
options() const867*3ac0a46fSAndroid Build Coastguard Worker   const Options& options() const { return processor_->options(); }
idler() const868*3ac0a46fSAndroid Build Coastguard Worker   const std::function<void()>& idler() const { return processor_->idler(); }
869*3ac0a46fSAndroid Build Coastguard Worker 
870*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
com_factory()871*3ac0a46fSAndroid Build Coastguard Worker   ComFactory& com_factory() { return processor_->com_factory(); }
872*3ac0a46fSAndroid Build Coastguard Worker #endif  // _WIN32
873*3ac0a46fSAndroid Build Coastguard Worker 
874*3ac0a46fSAndroid Build Coastguard Worker   // Per PDF state.
name() const875*3ac0a46fSAndroid Build Coastguard Worker   const std::string& name() const { return *name_; }
events() const876*3ac0a46fSAndroid Build Coastguard Worker   const std::string& events() const { return *events_; }
doc() const877*3ac0a46fSAndroid Build Coastguard Worker   FPDF_DOCUMENT doc() const { return doc_; }
form() const878*3ac0a46fSAndroid Build Coastguard Worker   FPDF_FORMHANDLE form() const { return form_; }
879*3ac0a46fSAndroid Build Coastguard Worker 
880*3ac0a46fSAndroid Build Coastguard Worker   // Invokes `idler()`.
Idle() const881*3ac0a46fSAndroid Build Coastguard Worker   void Idle() const { idler()(); }
882*3ac0a46fSAndroid Build Coastguard Worker 
GetPage(int page_index) const883*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE GetPage(int page_index) const {
884*3ac0a46fSAndroid Build Coastguard Worker     return GetPageForIndex(form_fill_info_, doc_, page_index);
885*3ac0a46fSAndroid Build Coastguard Worker   }
886*3ac0a46fSAndroid Build Coastguard Worker 
887*3ac0a46fSAndroid Build Coastguard Worker   Processor* processor_;
888*3ac0a46fSAndroid Build Coastguard Worker   const std::string* name_;
889*3ac0a46fSAndroid Build Coastguard Worker   const std::string* events_;
890*3ac0a46fSAndroid Build Coastguard Worker   FPDF_DOCUMENT doc_;
891*3ac0a46fSAndroid Build Coastguard Worker   FPDF_FORMHANDLE form_;
892*3ac0a46fSAndroid Build Coastguard Worker   FPDF_FORMFILLINFO_PDFiumTest* form_fill_info_;
893*3ac0a46fSAndroid Build Coastguard Worker };
894*3ac0a46fSAndroid Build Coastguard Worker 
895*3ac0a46fSAndroid Build Coastguard Worker // Page renderer with bitmap output.
896*3ac0a46fSAndroid Build Coastguard Worker class BitmapPageRenderer : public PageRenderer {
897*3ac0a46fSAndroid Build Coastguard Worker  public:
898*3ac0a46fSAndroid Build Coastguard Worker   // Function type that writes rendered output to a file, returning `false` on
899*3ac0a46fSAndroid Build Coastguard Worker   // failure.
900*3ac0a46fSAndroid Build Coastguard Worker   //
901*3ac0a46fSAndroid Build Coastguard Worker   // Intended to wrap functions from `pdfium_test_write_helper.h`.
902*3ac0a46fSAndroid Build Coastguard Worker   using PageWriter = std::function<bool(BitmapPageRenderer& renderer,
903*3ac0a46fSAndroid Build Coastguard Worker                                         const std::string& name,
904*3ac0a46fSAndroid Build Coastguard Worker                                         int page_index,
905*3ac0a46fSAndroid Build Coastguard Worker                                         bool md5)>;
906*3ac0a46fSAndroid Build Coastguard Worker 
907*3ac0a46fSAndroid Build Coastguard Worker   // Wraps a `PageWriter` around a function pointer that writes the text page.
WrapPageWriter(void (* text_page_writer)(FPDF_TEXTPAGE text_page,const char * pdf_name,int num))908*3ac0a46fSAndroid Build Coastguard Worker   static PageWriter WrapPageWriter(
909*3ac0a46fSAndroid Build Coastguard Worker       void (*text_page_writer)(FPDF_TEXTPAGE text_page,
910*3ac0a46fSAndroid Build Coastguard Worker                                const char* pdf_name,
911*3ac0a46fSAndroid Build Coastguard Worker                                int num)) {
912*3ac0a46fSAndroid Build Coastguard Worker     return [text_page_writer](BitmapPageRenderer& renderer,
913*3ac0a46fSAndroid Build Coastguard Worker                               const std::string& name, int page_index,
914*3ac0a46fSAndroid Build Coastguard Worker                               bool /*md5*/) {
915*3ac0a46fSAndroid Build Coastguard Worker       ScopedFPDFTextPage text_page(FPDFText_LoadPage(renderer.page()));
916*3ac0a46fSAndroid Build Coastguard Worker       if (!text_page) {
917*3ac0a46fSAndroid Build Coastguard Worker         return false;
918*3ac0a46fSAndroid Build Coastguard Worker       }
919*3ac0a46fSAndroid Build Coastguard Worker 
920*3ac0a46fSAndroid Build Coastguard Worker       text_page_writer(text_page.get(), name.c_str(), page_index);
921*3ac0a46fSAndroid Build Coastguard Worker       return true;
922*3ac0a46fSAndroid Build Coastguard Worker     };
923*3ac0a46fSAndroid Build Coastguard Worker   }
924*3ac0a46fSAndroid Build Coastguard Worker 
925*3ac0a46fSAndroid Build Coastguard Worker   // Wraps a `PageWriter` around a function pointer that writes the page.
WrapPageWriter(void (* page_writer)(FPDF_PAGE page,const char * pdf_name,int num))926*3ac0a46fSAndroid Build Coastguard Worker   static PageWriter WrapPageWriter(void (*page_writer)(FPDF_PAGE page,
927*3ac0a46fSAndroid Build Coastguard Worker                                                        const char* pdf_name,
928*3ac0a46fSAndroid Build Coastguard Worker                                                        int num)) {
929*3ac0a46fSAndroid Build Coastguard Worker     return [page_writer](BitmapPageRenderer& renderer, const std::string& name,
930*3ac0a46fSAndroid Build Coastguard Worker                          int page_index, bool /*md5*/) {
931*3ac0a46fSAndroid Build Coastguard Worker       page_writer(renderer.page(), name.c_str(), page_index);
932*3ac0a46fSAndroid Build Coastguard Worker       return true;
933*3ac0a46fSAndroid Build Coastguard Worker     };
934*3ac0a46fSAndroid Build Coastguard Worker   }
935*3ac0a46fSAndroid Build Coastguard Worker 
936*3ac0a46fSAndroid Build Coastguard Worker   // Wraps a `PageWriter` around a function pointer that writes the rasterized
937*3ac0a46fSAndroid Build Coastguard Worker   // bitmap to an image file.
WrapPageWriter(std::string (* bitmap_writer)(const char * pdf_name,int num,void * buffer,int stride,int width,int height))938*3ac0a46fSAndroid Build Coastguard Worker   static PageWriter WrapPageWriter(
939*3ac0a46fSAndroid Build Coastguard Worker       std::string (*bitmap_writer)(const char* pdf_name,
940*3ac0a46fSAndroid Build Coastguard Worker                                    int num,
941*3ac0a46fSAndroid Build Coastguard Worker                                    void* buffer,
942*3ac0a46fSAndroid Build Coastguard Worker                                    int stride,
943*3ac0a46fSAndroid Build Coastguard Worker                                    int width,
944*3ac0a46fSAndroid Build Coastguard Worker                                    int height)) {
945*3ac0a46fSAndroid Build Coastguard Worker     return [bitmap_writer](BitmapPageRenderer& renderer,
946*3ac0a46fSAndroid Build Coastguard Worker                            const std::string& name, int page_index, bool md5) {
947*3ac0a46fSAndroid Build Coastguard Worker       int stride = FPDFBitmap_GetStride(renderer.bitmap());
948*3ac0a46fSAndroid Build Coastguard Worker       void* buffer = FPDFBitmap_GetBuffer(renderer.bitmap());
949*3ac0a46fSAndroid Build Coastguard Worker       std::string image_file_name = bitmap_writer(
950*3ac0a46fSAndroid Build Coastguard Worker           name.c_str(), page_index, buffer, /*stride=*/stride,
951*3ac0a46fSAndroid Build Coastguard Worker           /*width=*/renderer.width(), /*height=*/renderer.height());
952*3ac0a46fSAndroid Build Coastguard Worker       if (image_file_name.empty()) {
953*3ac0a46fSAndroid Build Coastguard Worker         return false;
954*3ac0a46fSAndroid Build Coastguard Worker       }
955*3ac0a46fSAndroid Build Coastguard Worker 
956*3ac0a46fSAndroid Build Coastguard Worker       if (md5) {
957*3ac0a46fSAndroid Build Coastguard Worker         // Write the filename and the MD5 of the buffer to stdout.
958*3ac0a46fSAndroid Build Coastguard Worker         OutputMD5Hash(image_file_name.c_str(),
959*3ac0a46fSAndroid Build Coastguard Worker                       {static_cast<const uint8_t*>(buffer),
960*3ac0a46fSAndroid Build Coastguard Worker                        static_cast<size_t>(stride) * renderer.height()});
961*3ac0a46fSAndroid Build Coastguard Worker       }
962*3ac0a46fSAndroid Build Coastguard Worker       return true;
963*3ac0a46fSAndroid Build Coastguard Worker     };
964*3ac0a46fSAndroid Build Coastguard Worker   }
965*3ac0a46fSAndroid Build Coastguard Worker 
HasOutput() const966*3ac0a46fSAndroid Build Coastguard Worker   bool HasOutput() const override { return !!bitmap_; }
967*3ac0a46fSAndroid Build Coastguard Worker 
Finish(FPDF_FORMHANDLE form)968*3ac0a46fSAndroid Build Coastguard Worker   void Finish(FPDF_FORMHANDLE form) override {
969*3ac0a46fSAndroid Build Coastguard Worker     FPDF_FFLDraw(form, bitmap(), page(), /*start_x=*/0, /*start_y=*/0,
970*3ac0a46fSAndroid Build Coastguard Worker                  /*size_x=*/width(), /*size_y=*/height(), /*rotate=*/0,
971*3ac0a46fSAndroid Build Coastguard Worker                  /*flags=*/flags());
972*3ac0a46fSAndroid Build Coastguard Worker     Idle();
973*3ac0a46fSAndroid Build Coastguard Worker   }
974*3ac0a46fSAndroid Build Coastguard Worker 
Write(const std::string & name,int page_index,bool md5)975*3ac0a46fSAndroid Build Coastguard Worker   bool Write(const std::string& name, int page_index, bool md5) override {
976*3ac0a46fSAndroid Build Coastguard Worker     return writer_ && writer_(*this, name, page_index, md5);
977*3ac0a46fSAndroid Build Coastguard Worker   }
978*3ac0a46fSAndroid Build Coastguard Worker 
979*3ac0a46fSAndroid Build Coastguard Worker  protected:
BitmapPageRenderer(FPDF_PAGE page,int width,int height,int flags,const std::function<void ()> & idler,PageWriter writer)980*3ac0a46fSAndroid Build Coastguard Worker   BitmapPageRenderer(FPDF_PAGE page,
981*3ac0a46fSAndroid Build Coastguard Worker                      int width,
982*3ac0a46fSAndroid Build Coastguard Worker                      int height,
983*3ac0a46fSAndroid Build Coastguard Worker                      int flags,
984*3ac0a46fSAndroid Build Coastguard Worker                      const std::function<void()>& idler,
985*3ac0a46fSAndroid Build Coastguard Worker                      PageWriter writer)
986*3ac0a46fSAndroid Build Coastguard Worker       : PageRenderer(page, /*width=*/width, /*height=*/height, /*flags=*/flags),
987*3ac0a46fSAndroid Build Coastguard Worker         idler_(idler),
988*3ac0a46fSAndroid Build Coastguard Worker         writer_(std::move(writer)) {}
989*3ac0a46fSAndroid Build Coastguard Worker 
InitializeBitmap(void * first_scan)990*3ac0a46fSAndroid Build Coastguard Worker   bool InitializeBitmap(void* first_scan) {
991*3ac0a46fSAndroid Build Coastguard Worker     bool alpha = FPDFPage_HasTransparency(page());
992*3ac0a46fSAndroid Build Coastguard Worker     bitmap_.reset(FPDFBitmap_CreateEx(
993*3ac0a46fSAndroid Build Coastguard Worker         /*width=*/width(), /*height=*/height(),
994*3ac0a46fSAndroid Build Coastguard Worker         /*format=*/alpha ? FPDFBitmap_BGRA : FPDFBitmap_BGRx, first_scan,
995*3ac0a46fSAndroid Build Coastguard Worker         /*stride=*/width() * sizeof(uint32_t)));
996*3ac0a46fSAndroid Build Coastguard Worker     if (!bitmap()) {
997*3ac0a46fSAndroid Build Coastguard Worker       return false;
998*3ac0a46fSAndroid Build Coastguard Worker     }
999*3ac0a46fSAndroid Build Coastguard Worker 
1000*3ac0a46fSAndroid Build Coastguard Worker     FPDF_DWORD fill_color = alpha ? 0x00000000 : 0xFFFFFFFF;
1001*3ac0a46fSAndroid Build Coastguard Worker     FPDFBitmap_FillRect(bitmap(), /*left=*/0, /*top=*/0, /*width=*/width(),
1002*3ac0a46fSAndroid Build Coastguard Worker                         /*height=*/height(), /*color=*/fill_color);
1003*3ac0a46fSAndroid Build Coastguard Worker     return true;
1004*3ac0a46fSAndroid Build Coastguard Worker   }
1005*3ac0a46fSAndroid Build Coastguard Worker 
ResetBitmap()1006*3ac0a46fSAndroid Build Coastguard Worker   void ResetBitmap() { bitmap_.reset(); }
1007*3ac0a46fSAndroid Build Coastguard Worker 
Idle() const1008*3ac0a46fSAndroid Build Coastguard Worker   void Idle() const { idler_(); }
bitmap()1009*3ac0a46fSAndroid Build Coastguard Worker   FPDF_BITMAP bitmap() { return bitmap_.get(); }
1010*3ac0a46fSAndroid Build Coastguard Worker 
1011*3ac0a46fSAndroid Build Coastguard Worker  private:
1012*3ac0a46fSAndroid Build Coastguard Worker   const std::function<void()>& idler_;
1013*3ac0a46fSAndroid Build Coastguard Worker   PageWriter writer_;
1014*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFBitmap bitmap_;
1015*3ac0a46fSAndroid Build Coastguard Worker };
1016*3ac0a46fSAndroid Build Coastguard Worker 
1017*3ac0a46fSAndroid Build Coastguard Worker // Bitmap page renderer completing in a single operation.
1018*3ac0a46fSAndroid Build Coastguard Worker class OneShotBitmapPageRenderer : public BitmapPageRenderer {
1019*3ac0a46fSAndroid Build Coastguard Worker  public:
OneShotBitmapPageRenderer(FPDF_PAGE page,int width,int height,int flags,const std::function<void ()> & idler,PageWriter writer)1020*3ac0a46fSAndroid Build Coastguard Worker   OneShotBitmapPageRenderer(FPDF_PAGE page,
1021*3ac0a46fSAndroid Build Coastguard Worker                             int width,
1022*3ac0a46fSAndroid Build Coastguard Worker                             int height,
1023*3ac0a46fSAndroid Build Coastguard Worker                             int flags,
1024*3ac0a46fSAndroid Build Coastguard Worker                             const std::function<void()>& idler,
1025*3ac0a46fSAndroid Build Coastguard Worker                             PageWriter writer)
1026*3ac0a46fSAndroid Build Coastguard Worker       : BitmapPageRenderer(page,
1027*3ac0a46fSAndroid Build Coastguard Worker                            /*width=*/width,
1028*3ac0a46fSAndroid Build Coastguard Worker                            /*height=*/height,
1029*3ac0a46fSAndroid Build Coastguard Worker                            /*flags=*/flags,
1030*3ac0a46fSAndroid Build Coastguard Worker                            idler,
1031*3ac0a46fSAndroid Build Coastguard Worker                            std::move(writer)) {}
1032*3ac0a46fSAndroid Build Coastguard Worker 
Start()1033*3ac0a46fSAndroid Build Coastguard Worker   bool Start() override {
1034*3ac0a46fSAndroid Build Coastguard Worker     if (!InitializeBitmap(/*first_scan=*/nullptr)) {
1035*3ac0a46fSAndroid Build Coastguard Worker       return false;
1036*3ac0a46fSAndroid Build Coastguard Worker     }
1037*3ac0a46fSAndroid Build Coastguard Worker 
1038*3ac0a46fSAndroid Build Coastguard Worker     // Note, client programs probably want to use this method instead of the
1039*3ac0a46fSAndroid Build Coastguard Worker     // progressive calls. The progressive calls are if you need to pause the
1040*3ac0a46fSAndroid Build Coastguard Worker     // rendering to update the UI, the PDF renderer will break when possible.
1041*3ac0a46fSAndroid Build Coastguard Worker     FPDF_RenderPageBitmap(bitmap(), page(), /*start_x=*/0, /*start_y=*/0,
1042*3ac0a46fSAndroid Build Coastguard Worker                           /*size_x=*/width(), /*size_y=*/height(), /*rotate=*/0,
1043*3ac0a46fSAndroid Build Coastguard Worker                           /*flags=*/flags());
1044*3ac0a46fSAndroid Build Coastguard Worker     return true;
1045*3ac0a46fSAndroid Build Coastguard Worker   }
1046*3ac0a46fSAndroid Build Coastguard Worker };
1047*3ac0a46fSAndroid Build Coastguard Worker 
1048*3ac0a46fSAndroid Build Coastguard Worker // Bitmap page renderer completing over multiple operations.
1049*3ac0a46fSAndroid Build Coastguard Worker class ProgressiveBitmapPageRenderer : public BitmapPageRenderer {
1050*3ac0a46fSAndroid Build Coastguard Worker  public:
ProgressiveBitmapPageRenderer(FPDF_PAGE page,int width,int height,int flags,const std::function<void ()> & idler,PageWriter writer,const FPDF_COLORSCHEME * color_scheme)1051*3ac0a46fSAndroid Build Coastguard Worker   ProgressiveBitmapPageRenderer(FPDF_PAGE page,
1052*3ac0a46fSAndroid Build Coastguard Worker                                 int width,
1053*3ac0a46fSAndroid Build Coastguard Worker                                 int height,
1054*3ac0a46fSAndroid Build Coastguard Worker                                 int flags,
1055*3ac0a46fSAndroid Build Coastguard Worker                                 const std::function<void()>& idler,
1056*3ac0a46fSAndroid Build Coastguard Worker                                 PageWriter writer,
1057*3ac0a46fSAndroid Build Coastguard Worker                                 const FPDF_COLORSCHEME* color_scheme)
1058*3ac0a46fSAndroid Build Coastguard Worker       : BitmapPageRenderer(page,
1059*3ac0a46fSAndroid Build Coastguard Worker                            /*width=*/width,
1060*3ac0a46fSAndroid Build Coastguard Worker                            /*height=*/height,
1061*3ac0a46fSAndroid Build Coastguard Worker                            /*flags=*/flags,
1062*3ac0a46fSAndroid Build Coastguard Worker                            idler,
1063*3ac0a46fSAndroid Build Coastguard Worker                            std::move(writer)),
1064*3ac0a46fSAndroid Build Coastguard Worker         color_scheme_(color_scheme) {
1065*3ac0a46fSAndroid Build Coastguard Worker     pause_.version = 1;
1066*3ac0a46fSAndroid Build Coastguard Worker     pause_.NeedToPauseNow = &NeedToPauseNow;
1067*3ac0a46fSAndroid Build Coastguard Worker   }
1068*3ac0a46fSAndroid Build Coastguard Worker 
Start()1069*3ac0a46fSAndroid Build Coastguard Worker   bool Start() override {
1070*3ac0a46fSAndroid Build Coastguard Worker     if (!InitializeBitmap(/*first_scan=*/nullptr)) {
1071*3ac0a46fSAndroid Build Coastguard Worker       return false;
1072*3ac0a46fSAndroid Build Coastguard Worker     }
1073*3ac0a46fSAndroid Build Coastguard Worker 
1074*3ac0a46fSAndroid Build Coastguard Worker     if (FPDF_RenderPageBitmapWithColorScheme_Start(
1075*3ac0a46fSAndroid Build Coastguard Worker             bitmap(), page(), /*start_x=*/0, /*start_y=*/0, /*size_x=*/width(),
1076*3ac0a46fSAndroid Build Coastguard Worker             /*size_y=*/height(), /*rotate=*/0, /*flags=*/flags(), color_scheme_,
1077*3ac0a46fSAndroid Build Coastguard Worker             &pause_) == FPDF_RENDER_TOBECONTINUED) {
1078*3ac0a46fSAndroid Build Coastguard Worker       to_be_continued_ = true;
1079*3ac0a46fSAndroid Build Coastguard Worker     }
1080*3ac0a46fSAndroid Build Coastguard Worker     return true;
1081*3ac0a46fSAndroid Build Coastguard Worker   }
1082*3ac0a46fSAndroid Build Coastguard Worker 
Continue()1083*3ac0a46fSAndroid Build Coastguard Worker   bool Continue() override {
1084*3ac0a46fSAndroid Build Coastguard Worker     if (to_be_continued_) {
1085*3ac0a46fSAndroid Build Coastguard Worker       to_be_continued_ = (FPDF_RenderPage_Continue(page(), &pause_) ==
1086*3ac0a46fSAndroid Build Coastguard Worker                           FPDF_RENDER_TOBECONTINUED);
1087*3ac0a46fSAndroid Build Coastguard Worker     }
1088*3ac0a46fSAndroid Build Coastguard Worker     return to_be_continued_;
1089*3ac0a46fSAndroid Build Coastguard Worker   }
1090*3ac0a46fSAndroid Build Coastguard Worker 
Finish(FPDF_FORMHANDLE form)1091*3ac0a46fSAndroid Build Coastguard Worker   void Finish(FPDF_FORMHANDLE form) override {
1092*3ac0a46fSAndroid Build Coastguard Worker     BitmapPageRenderer::Finish(form);
1093*3ac0a46fSAndroid Build Coastguard Worker     FPDF_RenderPage_Close(page());
1094*3ac0a46fSAndroid Build Coastguard Worker     Idle();
1095*3ac0a46fSAndroid Build Coastguard Worker   }
1096*3ac0a46fSAndroid Build Coastguard Worker 
1097*3ac0a46fSAndroid Build Coastguard Worker  private:
1098*3ac0a46fSAndroid Build Coastguard Worker   const FPDF_COLORSCHEME* color_scheme_;
1099*3ac0a46fSAndroid Build Coastguard Worker   IFSDK_PAUSE pause_;
1100*3ac0a46fSAndroid Build Coastguard Worker   bool to_be_continued_ = false;
1101*3ac0a46fSAndroid Build Coastguard Worker };
1102*3ac0a46fSAndroid Build Coastguard Worker 
1103*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
1104*3ac0a46fSAndroid Build Coastguard Worker class ScopedGdiDc final {
1105*3ac0a46fSAndroid Build Coastguard Worker  public:
~ScopedGdiDc()1106*3ac0a46fSAndroid Build Coastguard Worker   ~ScopedGdiDc() { Reset(nullptr); }
1107*3ac0a46fSAndroid Build Coastguard Worker 
Reset(HDC dc)1108*3ac0a46fSAndroid Build Coastguard Worker   void Reset(HDC dc) {
1109*3ac0a46fSAndroid Build Coastguard Worker     if (dc_) {
1110*3ac0a46fSAndroid Build Coastguard Worker       [[maybe_unused]] BOOL success = DeleteDC(dc_);
1111*3ac0a46fSAndroid Build Coastguard Worker       DCHECK(success);
1112*3ac0a46fSAndroid Build Coastguard Worker     }
1113*3ac0a46fSAndroid Build Coastguard Worker     dc_ = dc;
1114*3ac0a46fSAndroid Build Coastguard Worker   }
1115*3ac0a46fSAndroid Build Coastguard Worker 
Get() const1116*3ac0a46fSAndroid Build Coastguard Worker   HDC Get() const { return dc_; }
1117*3ac0a46fSAndroid Build Coastguard Worker 
1118*3ac0a46fSAndroid Build Coastguard Worker  private:
1119*3ac0a46fSAndroid Build Coastguard Worker   HDC dc_ = nullptr;
1120*3ac0a46fSAndroid Build Coastguard Worker };
1121*3ac0a46fSAndroid Build Coastguard Worker 
1122*3ac0a46fSAndroid Build Coastguard Worker class ScopedGdiObject final {
1123*3ac0a46fSAndroid Build Coastguard Worker  public:
~ScopedGdiObject()1124*3ac0a46fSAndroid Build Coastguard Worker   ~ScopedGdiObject() { Reset(nullptr); }
1125*3ac0a46fSAndroid Build Coastguard Worker 
Reset(HGDIOBJ object)1126*3ac0a46fSAndroid Build Coastguard Worker   void Reset(HGDIOBJ object) {
1127*3ac0a46fSAndroid Build Coastguard Worker     if (object_) {
1128*3ac0a46fSAndroid Build Coastguard Worker       [[maybe_unused]] BOOL success = DeleteObject(object_);
1129*3ac0a46fSAndroid Build Coastguard Worker       DCHECK(success);
1130*3ac0a46fSAndroid Build Coastguard Worker     }
1131*3ac0a46fSAndroid Build Coastguard Worker     object_ = object;
1132*3ac0a46fSAndroid Build Coastguard Worker   }
1133*3ac0a46fSAndroid Build Coastguard Worker 
Get() const1134*3ac0a46fSAndroid Build Coastguard Worker   HGDIOBJ Get() const { return object_; }
1135*3ac0a46fSAndroid Build Coastguard Worker 
1136*3ac0a46fSAndroid Build Coastguard Worker  private:
1137*3ac0a46fSAndroid Build Coastguard Worker   HGDIOBJ object_ = nullptr;
1138*3ac0a46fSAndroid Build Coastguard Worker };
1139*3ac0a46fSAndroid Build Coastguard Worker 
1140*3ac0a46fSAndroid Build Coastguard Worker class GdiDisplayPageRenderer : public BitmapPageRenderer {
1141*3ac0a46fSAndroid Build Coastguard Worker  public:
GdiDisplayPageRenderer(FPDF_PAGE page,int width,int height,int flags,const std::function<void ()> & idler,PageWriter writer)1142*3ac0a46fSAndroid Build Coastguard Worker   GdiDisplayPageRenderer(FPDF_PAGE page,
1143*3ac0a46fSAndroid Build Coastguard Worker                          int width,
1144*3ac0a46fSAndroid Build Coastguard Worker                          int height,
1145*3ac0a46fSAndroid Build Coastguard Worker                          int flags,
1146*3ac0a46fSAndroid Build Coastguard Worker                          const std::function<void()>& idler,
1147*3ac0a46fSAndroid Build Coastguard Worker                          PageWriter writer)
1148*3ac0a46fSAndroid Build Coastguard Worker       : BitmapPageRenderer(page,
1149*3ac0a46fSAndroid Build Coastguard Worker                            /*width=*/width,
1150*3ac0a46fSAndroid Build Coastguard Worker                            /*height=*/height,
1151*3ac0a46fSAndroid Build Coastguard Worker                            /*flags=*/flags,
1152*3ac0a46fSAndroid Build Coastguard Worker                            idler,
1153*3ac0a46fSAndroid Build Coastguard Worker                            std::move(writer)) {}
1154*3ac0a46fSAndroid Build Coastguard Worker 
~GdiDisplayPageRenderer()1155*3ac0a46fSAndroid Build Coastguard Worker   ~GdiDisplayPageRenderer() override {
1156*3ac0a46fSAndroid Build Coastguard Worker     // Need to free `bitmap()` first, in case it points at `dib_` memory.
1157*3ac0a46fSAndroid Build Coastguard Worker     ResetBitmap();
1158*3ac0a46fSAndroid Build Coastguard Worker   }
1159*3ac0a46fSAndroid Build Coastguard Worker 
Start()1160*3ac0a46fSAndroid Build Coastguard Worker   bool Start() override {
1161*3ac0a46fSAndroid Build Coastguard Worker     // Create an in-memory DC compatible with the display.
1162*3ac0a46fSAndroid Build Coastguard Worker     dc_.Reset(CreateCompatibleDC(/*hdc=*/nullptr));
1163*3ac0a46fSAndroid Build Coastguard Worker     if (!dc_.Get()) {
1164*3ac0a46fSAndroid Build Coastguard Worker       return false;
1165*3ac0a46fSAndroid Build Coastguard Worker     }
1166*3ac0a46fSAndroid Build Coastguard Worker 
1167*3ac0a46fSAndroid Build Coastguard Worker     // Create a BGRA DIB and select it into the in-memory DC.
1168*3ac0a46fSAndroid Build Coastguard Worker     BITMAPINFO dib_info;
1169*3ac0a46fSAndroid Build Coastguard Worker     memset(&dib_info, 0, sizeof(BITMAPINFO));
1170*3ac0a46fSAndroid Build Coastguard Worker     dib_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1171*3ac0a46fSAndroid Build Coastguard Worker     dib_info.bmiHeader.biWidth = width();
1172*3ac0a46fSAndroid Build Coastguard Worker     dib_info.bmiHeader.biHeight = -height();  // top-down
1173*3ac0a46fSAndroid Build Coastguard Worker     dib_info.bmiHeader.biPlanes = 1;
1174*3ac0a46fSAndroid Build Coastguard Worker     dib_info.bmiHeader.biBitCount = 32;
1175*3ac0a46fSAndroid Build Coastguard Worker     dib_info.bmiHeader.biCompression = BI_RGB;
1176*3ac0a46fSAndroid Build Coastguard Worker 
1177*3ac0a46fSAndroid Build Coastguard Worker     VOID* dib_pixels;
1178*3ac0a46fSAndroid Build Coastguard Worker     dib_.Reset(CreateDIBSection(dc_.Get(), &dib_info, DIB_RGB_COLORS,
1179*3ac0a46fSAndroid Build Coastguard Worker                                 &dib_pixels, /*hSection=*/nullptr,
1180*3ac0a46fSAndroid Build Coastguard Worker                                 /*offset=*/0));
1181*3ac0a46fSAndroid Build Coastguard Worker     if (!dib_.Get() || !InitializeBitmap(dib_pixels)) {
1182*3ac0a46fSAndroid Build Coastguard Worker       return false;
1183*3ac0a46fSAndroid Build Coastguard Worker     }
1184*3ac0a46fSAndroid Build Coastguard Worker     pdfium::base::win::ScopedSelectObject select_dib(dc_.Get(), dib_.Get());
1185*3ac0a46fSAndroid Build Coastguard Worker 
1186*3ac0a46fSAndroid Build Coastguard Worker     // Render into the in-memory DC.
1187*3ac0a46fSAndroid Build Coastguard Worker     FPDF_RenderPage(dc_.Get(), page(), /*start_x=*/0, /*start_y=*/0,
1188*3ac0a46fSAndroid Build Coastguard Worker                     /*size_x=*/width(), /*size_y=*/height(), /*rotate=*/0,
1189*3ac0a46fSAndroid Build Coastguard Worker                     /*flags=*/flags());
1190*3ac0a46fSAndroid Build Coastguard Worker 
1191*3ac0a46fSAndroid Build Coastguard Worker     return !!GdiFlush();
1192*3ac0a46fSAndroid Build Coastguard Worker   }
1193*3ac0a46fSAndroid Build Coastguard Worker 
Finish(FPDF_FORMHANDLE)1194*3ac0a46fSAndroid Build Coastguard Worker   void Finish(FPDF_FORMHANDLE /*form*/) override {
1195*3ac0a46fSAndroid Build Coastguard Worker     // Note that `fpdf_formfill.h` does not support GDI.
1196*3ac0a46fSAndroid Build Coastguard Worker 
1197*3ac0a46fSAndroid Build Coastguard Worker     // The GDI backend doesn't support alpha and clears the alpha component to
1198*3ac0a46fSAndroid Build Coastguard Worker     // transparent, so clear the alpha component back to opaque.
1199*3ac0a46fSAndroid Build Coastguard Worker     const int stride = FPDFBitmap_GetStride(bitmap());
1200*3ac0a46fSAndroid Build Coastguard Worker     DCHECK_EQ(width() * sizeof(uint32_t), static_cast<size_t>(stride));
1201*3ac0a46fSAndroid Build Coastguard Worker     const int pixel_stride = stride / sizeof(uint32_t);
1202*3ac0a46fSAndroid Build Coastguard Worker 
1203*3ac0a46fSAndroid Build Coastguard Worker     uint32_t* scanline =
1204*3ac0a46fSAndroid Build Coastguard Worker         reinterpret_cast<uint32_t*>(FPDFBitmap_GetBuffer(bitmap()));
1205*3ac0a46fSAndroid Build Coastguard Worker     for (int row = 0; row < height(); ++row) {
1206*3ac0a46fSAndroid Build Coastguard Worker       for (int column = 0; column < width(); ++column) {
1207*3ac0a46fSAndroid Build Coastguard Worker         scanline[column] |= 0xFF000000;
1208*3ac0a46fSAndroid Build Coastguard Worker       }
1209*3ac0a46fSAndroid Build Coastguard Worker       scanline += pixel_stride;
1210*3ac0a46fSAndroid Build Coastguard Worker     }
1211*3ac0a46fSAndroid Build Coastguard Worker   }
1212*3ac0a46fSAndroid Build Coastguard Worker 
1213*3ac0a46fSAndroid Build Coastguard Worker  private:
1214*3ac0a46fSAndroid Build Coastguard Worker   ScopedGdiDc dc_;
1215*3ac0a46fSAndroid Build Coastguard Worker   ScopedGdiObject dib_;
1216*3ac0a46fSAndroid Build Coastguard Worker };
1217*3ac0a46fSAndroid Build Coastguard Worker #endif  // _WIN32
1218*3ac0a46fSAndroid Build Coastguard Worker 
1219*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_SKIA
1220*3ac0a46fSAndroid Build Coastguard Worker class SkCanvasPageRenderer : public PageRenderer {
1221*3ac0a46fSAndroid Build Coastguard Worker  public:
Start()1222*3ac0a46fSAndroid Build Coastguard Worker   bool Start() override {
1223*3ac0a46fSAndroid Build Coastguard Worker     FPDF_RenderPageSkia(reinterpret_cast<FPDF_SKIA_CANVAS>(canvas()), page(),
1224*3ac0a46fSAndroid Build Coastguard Worker                         width(), height());
1225*3ac0a46fSAndroid Build Coastguard Worker     return true;
1226*3ac0a46fSAndroid Build Coastguard Worker   }
1227*3ac0a46fSAndroid Build Coastguard Worker 
Finish(FPDF_FORMHANDLE form)1228*3ac0a46fSAndroid Build Coastguard Worker   void Finish(FPDF_FORMHANDLE form) override {
1229*3ac0a46fSAndroid Build Coastguard Worker     FPDF_FFLDrawSkia(form, reinterpret_cast<FPDF_SKIA_CANVAS>(canvas()), page(),
1230*3ac0a46fSAndroid Build Coastguard Worker                      /*start_x=*/0, /*start_y=*/0, width(), height(),
1231*3ac0a46fSAndroid Build Coastguard Worker                      /*rotate=*/0, flags());
1232*3ac0a46fSAndroid Build Coastguard Worker   }
1233*3ac0a46fSAndroid Build Coastguard Worker 
1234*3ac0a46fSAndroid Build Coastguard Worker  protected:
SkCanvasPageRenderer(FPDF_PAGE page,int width,int height,int flags)1235*3ac0a46fSAndroid Build Coastguard Worker   SkCanvasPageRenderer(FPDF_PAGE page, int width, int height, int flags)
1236*3ac0a46fSAndroid Build Coastguard Worker       : PageRenderer(page, width, height, flags) {}
1237*3ac0a46fSAndroid Build Coastguard Worker 
1238*3ac0a46fSAndroid Build Coastguard Worker   virtual SkCanvas* canvas() = 0;
1239*3ac0a46fSAndroid Build Coastguard Worker };
1240*3ac0a46fSAndroid Build Coastguard Worker 
1241*3ac0a46fSAndroid Build Coastguard Worker class SkPicturePageRenderer final : public SkCanvasPageRenderer {
1242*3ac0a46fSAndroid Build Coastguard Worker  public:
SkPicturePageRenderer(FPDF_PAGE page,int width,int height,int flags)1243*3ac0a46fSAndroid Build Coastguard Worker   SkPicturePageRenderer(FPDF_PAGE page, int width, int height, int flags)
1244*3ac0a46fSAndroid Build Coastguard Worker       : SkCanvasPageRenderer(page, width, height, flags) {}
1245*3ac0a46fSAndroid Build Coastguard Worker 
HasOutput() const1246*3ac0a46fSAndroid Build Coastguard Worker   bool HasOutput() const override { return !!picture_; }
1247*3ac0a46fSAndroid Build Coastguard Worker 
Start()1248*3ac0a46fSAndroid Build Coastguard Worker   bool Start() override {
1249*3ac0a46fSAndroid Build Coastguard Worker     recorder_ = std::make_unique<SkPictureRecorder>();
1250*3ac0a46fSAndroid Build Coastguard Worker     recorder_->beginRecording(width(), height());
1251*3ac0a46fSAndroid Build Coastguard Worker     return SkCanvasPageRenderer::Start();
1252*3ac0a46fSAndroid Build Coastguard Worker   }
1253*3ac0a46fSAndroid Build Coastguard Worker 
Finish(FPDF_FORMHANDLE form)1254*3ac0a46fSAndroid Build Coastguard Worker   void Finish(FPDF_FORMHANDLE form) override {
1255*3ac0a46fSAndroid Build Coastguard Worker     SkCanvasPageRenderer::Finish(form);
1256*3ac0a46fSAndroid Build Coastguard Worker     picture_ = recorder_->finishRecordingAsPicture();
1257*3ac0a46fSAndroid Build Coastguard Worker     recorder_.reset();
1258*3ac0a46fSAndroid Build Coastguard Worker   }
1259*3ac0a46fSAndroid Build Coastguard Worker 
Write(const std::string & name,int page_index,bool md5)1260*3ac0a46fSAndroid Build Coastguard Worker   bool Write(const std::string& name, int page_index, bool md5) override {
1261*3ac0a46fSAndroid Build Coastguard Worker     std::string image_file_name = WriteSkp(name.c_str(), page_index, *picture_);
1262*3ac0a46fSAndroid Build Coastguard Worker     if (image_file_name.empty())
1263*3ac0a46fSAndroid Build Coastguard Worker       return false;
1264*3ac0a46fSAndroid Build Coastguard Worker 
1265*3ac0a46fSAndroid Build Coastguard Worker     if (md5) {
1266*3ac0a46fSAndroid Build Coastguard Worker       // Play back the `SkPicture` so we can take a hash of the result.
1267*3ac0a46fSAndroid Build Coastguard Worker       sk_sp<SkSurface> surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(
1268*3ac0a46fSAndroid Build Coastguard Worker           /*width=*/width(), /*height=*/height()));
1269*3ac0a46fSAndroid Build Coastguard Worker       if (!surface)
1270*3ac0a46fSAndroid Build Coastguard Worker         return false;
1271*3ac0a46fSAndroid Build Coastguard Worker 
1272*3ac0a46fSAndroid Build Coastguard Worker       // Must clear to white before replay to match initial `CFX_DIBitmap`.
1273*3ac0a46fSAndroid Build Coastguard Worker       surface->getCanvas()->clear(SK_ColorWHITE);
1274*3ac0a46fSAndroid Build Coastguard Worker       surface->getCanvas()->drawPicture(picture_);
1275*3ac0a46fSAndroid Build Coastguard Worker 
1276*3ac0a46fSAndroid Build Coastguard Worker       // Write the filename and the MD5 of the buffer to stdout.
1277*3ac0a46fSAndroid Build Coastguard Worker       SkPixmap pixmap;
1278*3ac0a46fSAndroid Build Coastguard Worker       if (!surface->peekPixels(&pixmap))
1279*3ac0a46fSAndroid Build Coastguard Worker         return false;
1280*3ac0a46fSAndroid Build Coastguard Worker 
1281*3ac0a46fSAndroid Build Coastguard Worker       OutputMD5Hash(image_file_name.c_str(),
1282*3ac0a46fSAndroid Build Coastguard Worker                     {static_cast<const uint8_t*>(pixmap.addr()),
1283*3ac0a46fSAndroid Build Coastguard Worker                      pixmap.computeByteSize()});
1284*3ac0a46fSAndroid Build Coastguard Worker     }
1285*3ac0a46fSAndroid Build Coastguard Worker     return true;
1286*3ac0a46fSAndroid Build Coastguard Worker   }
1287*3ac0a46fSAndroid Build Coastguard Worker 
1288*3ac0a46fSAndroid Build Coastguard Worker  protected:
canvas()1289*3ac0a46fSAndroid Build Coastguard Worker   SkCanvas* canvas() override { return recorder_->getRecordingCanvas(); }
1290*3ac0a46fSAndroid Build Coastguard Worker 
1291*3ac0a46fSAndroid Build Coastguard Worker  private:
1292*3ac0a46fSAndroid Build Coastguard Worker   std::unique_ptr<SkPictureRecorder> recorder_;
1293*3ac0a46fSAndroid Build Coastguard Worker   sk_sp<SkPicture> picture_;
1294*3ac0a46fSAndroid Build Coastguard Worker };
1295*3ac0a46fSAndroid Build Coastguard Worker 
1296*3ac0a46fSAndroid Build Coastguard Worker class SkDocumentPageRenderer final : public SkCanvasPageRenderer {
1297*3ac0a46fSAndroid Build Coastguard Worker  public:
SkDocumentPageRenderer(std::unique_ptr<SkWStream> stream,sk_sp<SkDocument> document,FPDF_PAGE page,int width,int height,int flags)1298*3ac0a46fSAndroid Build Coastguard Worker   SkDocumentPageRenderer(std::unique_ptr<SkWStream> stream,
1299*3ac0a46fSAndroid Build Coastguard Worker                          sk_sp<SkDocument> document,
1300*3ac0a46fSAndroid Build Coastguard Worker                          FPDF_PAGE page,
1301*3ac0a46fSAndroid Build Coastguard Worker                          int width,
1302*3ac0a46fSAndroid Build Coastguard Worker                          int height,
1303*3ac0a46fSAndroid Build Coastguard Worker                          int flags)
1304*3ac0a46fSAndroid Build Coastguard Worker       : SkCanvasPageRenderer(page, width, height, flags),
1305*3ac0a46fSAndroid Build Coastguard Worker         stream_(std::move(stream)),
1306*3ac0a46fSAndroid Build Coastguard Worker         document_(std::move(document)) {
1307*3ac0a46fSAndroid Build Coastguard Worker     DCHECK(stream_);
1308*3ac0a46fSAndroid Build Coastguard Worker     DCHECK(document_);
1309*3ac0a46fSAndroid Build Coastguard Worker   }
1310*3ac0a46fSAndroid Build Coastguard Worker 
HasOutput() const1311*3ac0a46fSAndroid Build Coastguard Worker   bool HasOutput() const override { return has_output_; }
1312*3ac0a46fSAndroid Build Coastguard Worker 
Start()1313*3ac0a46fSAndroid Build Coastguard Worker   bool Start() override {
1314*3ac0a46fSAndroid Build Coastguard Worker     if (!document_) {
1315*3ac0a46fSAndroid Build Coastguard Worker       return false;
1316*3ac0a46fSAndroid Build Coastguard Worker     }
1317*3ac0a46fSAndroid Build Coastguard Worker 
1318*3ac0a46fSAndroid Build Coastguard Worker     DCHECK(!canvas_);
1319*3ac0a46fSAndroid Build Coastguard Worker     canvas_ = document_->beginPage(width(), height());
1320*3ac0a46fSAndroid Build Coastguard Worker     if (!canvas_) {
1321*3ac0a46fSAndroid Build Coastguard Worker       return false;
1322*3ac0a46fSAndroid Build Coastguard Worker     }
1323*3ac0a46fSAndroid Build Coastguard Worker 
1324*3ac0a46fSAndroid Build Coastguard Worker     return SkCanvasPageRenderer::Start();
1325*3ac0a46fSAndroid Build Coastguard Worker   }
1326*3ac0a46fSAndroid Build Coastguard Worker 
Finish(FPDF_FORMHANDLE form)1327*3ac0a46fSAndroid Build Coastguard Worker   void Finish(FPDF_FORMHANDLE form) override {
1328*3ac0a46fSAndroid Build Coastguard Worker     SkCanvasPageRenderer::Finish(form);
1329*3ac0a46fSAndroid Build Coastguard Worker 
1330*3ac0a46fSAndroid Build Coastguard Worker     DCHECK(canvas_);
1331*3ac0a46fSAndroid Build Coastguard Worker     canvas_ = nullptr;
1332*3ac0a46fSAndroid Build Coastguard Worker     document_->endPage();
1333*3ac0a46fSAndroid Build Coastguard Worker 
1334*3ac0a46fSAndroid Build Coastguard Worker     has_output_ = true;
1335*3ac0a46fSAndroid Build Coastguard Worker   }
1336*3ac0a46fSAndroid Build Coastguard Worker 
Write(const std::string &,int,bool)1337*3ac0a46fSAndroid Build Coastguard Worker   bool Write(const std::string& /*name*/,
1338*3ac0a46fSAndroid Build Coastguard Worker              int /*page_index*/,
1339*3ac0a46fSAndroid Build Coastguard Worker              bool /*md5*/) override {
1340*3ac0a46fSAndroid Build Coastguard Worker     bool success = HasOutput();
1341*3ac0a46fSAndroid Build Coastguard Worker     if (success) {
1342*3ac0a46fSAndroid Build Coastguard Worker       document_->close();
1343*3ac0a46fSAndroid Build Coastguard Worker     } else {
1344*3ac0a46fSAndroid Build Coastguard Worker       document_->abort();
1345*3ac0a46fSAndroid Build Coastguard Worker     }
1346*3ac0a46fSAndroid Build Coastguard Worker 
1347*3ac0a46fSAndroid Build Coastguard Worker     document_.reset();
1348*3ac0a46fSAndroid Build Coastguard Worker     stream_.reset();
1349*3ac0a46fSAndroid Build Coastguard Worker     return success;
1350*3ac0a46fSAndroid Build Coastguard Worker   }
1351*3ac0a46fSAndroid Build Coastguard Worker 
1352*3ac0a46fSAndroid Build Coastguard Worker  protected:
canvas()1353*3ac0a46fSAndroid Build Coastguard Worker   SkCanvas* canvas() override { return canvas_; }
1354*3ac0a46fSAndroid Build Coastguard Worker 
1355*3ac0a46fSAndroid Build Coastguard Worker  private:
1356*3ac0a46fSAndroid Build Coastguard Worker   std::unique_ptr<SkWStream> stream_;
1357*3ac0a46fSAndroid Build Coastguard Worker   sk_sp<SkDocument> document_;
1358*3ac0a46fSAndroid Build Coastguard Worker 
1359*3ac0a46fSAndroid Build Coastguard Worker   SkCanvas* canvas_ = nullptr;
1360*3ac0a46fSAndroid Build Coastguard Worker   bool has_output_ = false;
1361*3ac0a46fSAndroid Build Coastguard Worker };
1362*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_SKIA
1363*3ac0a46fSAndroid Build Coastguard Worker 
ProcessPage(const int page_index)1364*3ac0a46fSAndroid Build Coastguard Worker bool PdfProcessor::ProcessPage(const int page_index) {
1365*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = GetPage(page_index);
1366*3ac0a46fSAndroid Build Coastguard Worker   if (!page) {
1367*3ac0a46fSAndroid Build Coastguard Worker     return false;
1368*3ac0a46fSAndroid Build Coastguard Worker   }
1369*3ac0a46fSAndroid Build Coastguard Worker 
1370*3ac0a46fSAndroid Build Coastguard Worker   if (options().send_events) {
1371*3ac0a46fSAndroid Build Coastguard Worker     SendPageEvents(form(), page, events(), idler());
1372*3ac0a46fSAndroid Build Coastguard Worker   }
1373*3ac0a46fSAndroid Build Coastguard Worker   if (options().save_images) {
1374*3ac0a46fSAndroid Build Coastguard Worker     WriteImages(page, name().c_str(), page_index);
1375*3ac0a46fSAndroid Build Coastguard Worker   }
1376*3ac0a46fSAndroid Build Coastguard Worker   if (options().save_rendered_images) {
1377*3ac0a46fSAndroid Build Coastguard Worker     WriteRenderedImages(doc(), page, name().c_str(), page_index);
1378*3ac0a46fSAndroid Build Coastguard Worker   }
1379*3ac0a46fSAndroid Build Coastguard Worker   if (options().save_thumbnails) {
1380*3ac0a46fSAndroid Build Coastguard Worker     WriteThumbnail(page, name().c_str(), page_index);
1381*3ac0a46fSAndroid Build Coastguard Worker   }
1382*3ac0a46fSAndroid Build Coastguard Worker   if (options().save_thumbnails_decoded) {
1383*3ac0a46fSAndroid Build Coastguard Worker     WriteDecodedThumbnailStream(page, name().c_str(), page_index);
1384*3ac0a46fSAndroid Build Coastguard Worker   }
1385*3ac0a46fSAndroid Build Coastguard Worker   if (options().save_thumbnails_raw) {
1386*3ac0a46fSAndroid Build Coastguard Worker     WriteRawThumbnailStream(page, name().c_str(), page_index);
1387*3ac0a46fSAndroid Build Coastguard Worker   }
1388*3ac0a46fSAndroid Build Coastguard Worker   if (options().output_format == OutputFormat::kPageInfo) {
1389*3ac0a46fSAndroid Build Coastguard Worker     DumpPageInfo(page, page_index);
1390*3ac0a46fSAndroid Build Coastguard Worker     return true;
1391*3ac0a46fSAndroid Build Coastguard Worker   }
1392*3ac0a46fSAndroid Build Coastguard Worker   if (options().output_format == OutputFormat::kStructure) {
1393*3ac0a46fSAndroid Build Coastguard Worker     DumpPageStructure(page, page_index);
1394*3ac0a46fSAndroid Build Coastguard Worker     return true;
1395*3ac0a46fSAndroid Build Coastguard Worker   }
1396*3ac0a46fSAndroid Build Coastguard Worker 
1397*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFTextPage text_page(FPDFText_LoadPage(page));
1398*3ac0a46fSAndroid Build Coastguard Worker   double scale = 1.0;
1399*3ac0a46fSAndroid Build Coastguard Worker   if (!options().scale_factor_as_string.empty()) {
1400*3ac0a46fSAndroid Build Coastguard Worker     std::stringstream(options().scale_factor_as_string) >> scale;
1401*3ac0a46fSAndroid Build Coastguard Worker   }
1402*3ac0a46fSAndroid Build Coastguard Worker 
1403*3ac0a46fSAndroid Build Coastguard Worker   int width = static_cast<int>(FPDF_GetPageWidthF(page) * scale);
1404*3ac0a46fSAndroid Build Coastguard Worker   int height = static_cast<int>(FPDF_GetPageHeightF(page) * scale);
1405*3ac0a46fSAndroid Build Coastguard Worker   int flags = PageRenderFlagsFromOptions(options());
1406*3ac0a46fSAndroid Build Coastguard Worker 
1407*3ac0a46fSAndroid Build Coastguard Worker   std::unique_ptr<PageRenderer> renderer;
1408*3ac0a46fSAndroid Build Coastguard Worker   BitmapPageRenderer::PageWriter writer;
1409*3ac0a46fSAndroid Build Coastguard Worker   switch (options().output_format) {
1410*3ac0a46fSAndroid Build Coastguard Worker     case OutputFormat::kText:
1411*3ac0a46fSAndroid Build Coastguard Worker       writer = BitmapPageRenderer::WrapPageWriter(WriteText);
1412*3ac0a46fSAndroid Build Coastguard Worker       break;
1413*3ac0a46fSAndroid Build Coastguard Worker 
1414*3ac0a46fSAndroid Build Coastguard Worker     case OutputFormat::kAnnot:
1415*3ac0a46fSAndroid Build Coastguard Worker       writer = BitmapPageRenderer::WrapPageWriter(WriteAnnot);
1416*3ac0a46fSAndroid Build Coastguard Worker       break;
1417*3ac0a46fSAndroid Build Coastguard Worker 
1418*3ac0a46fSAndroid Build Coastguard Worker     case OutputFormat::kPpm:
1419*3ac0a46fSAndroid Build Coastguard Worker       writer = BitmapPageRenderer::WrapPageWriter(WritePpm);
1420*3ac0a46fSAndroid Build Coastguard Worker       break;
1421*3ac0a46fSAndroid Build Coastguard Worker 
1422*3ac0a46fSAndroid Build Coastguard Worker     case OutputFormat::kPng:
1423*3ac0a46fSAndroid Build Coastguard Worker       writer = BitmapPageRenderer::WrapPageWriter(WritePng);
1424*3ac0a46fSAndroid Build Coastguard Worker       break;
1425*3ac0a46fSAndroid Build Coastguard Worker 
1426*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
1427*3ac0a46fSAndroid Build Coastguard Worker     case OutputFormat::kBmp:
1428*3ac0a46fSAndroid Build Coastguard Worker       writer = BitmapPageRenderer::WrapPageWriter(WriteBmp);
1429*3ac0a46fSAndroid Build Coastguard Worker       break;
1430*3ac0a46fSAndroid Build Coastguard Worker 
1431*3ac0a46fSAndroid Build Coastguard Worker     case OutputFormat::kEmf:
1432*3ac0a46fSAndroid Build Coastguard Worker       // TODO(crbug.com/pdfium/2054): Render directly to DC.
1433*3ac0a46fSAndroid Build Coastguard Worker       writer = BitmapPageRenderer::WrapPageWriter(WriteEmf);
1434*3ac0a46fSAndroid Build Coastguard Worker       break;
1435*3ac0a46fSAndroid Build Coastguard Worker 
1436*3ac0a46fSAndroid Build Coastguard Worker     case OutputFormat::kPs2:
1437*3ac0a46fSAndroid Build Coastguard Worker     case OutputFormat::kPs3:
1438*3ac0a46fSAndroid Build Coastguard Worker       // TODO(crbug.com/pdfium/2054): Render directly to DC.
1439*3ac0a46fSAndroid Build Coastguard Worker       writer = BitmapPageRenderer::WrapPageWriter(WritePS);
1440*3ac0a46fSAndroid Build Coastguard Worker       break;
1441*3ac0a46fSAndroid Build Coastguard Worker #endif  // _WIN32
1442*3ac0a46fSAndroid Build Coastguard Worker 
1443*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_SKIA
1444*3ac0a46fSAndroid Build Coastguard Worker     case OutputFormat::kSkp:
1445*3ac0a46fSAndroid Build Coastguard Worker       renderer = std::make_unique<SkPicturePageRenderer>(
1446*3ac0a46fSAndroid Build Coastguard Worker           page, /*width=*/width, /*height=*/height, /*flags=*/flags);
1447*3ac0a46fSAndroid Build Coastguard Worker       break;
1448*3ac0a46fSAndroid Build Coastguard Worker 
1449*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
1450*3ac0a46fSAndroid Build Coastguard Worker     case OutputFormat::kXps: {
1451*3ac0a46fSAndroid Build Coastguard Worker       IXpsOMObjectFactory* xps_factory = com_factory().GetXpsOMObjectFactory();
1452*3ac0a46fSAndroid Build Coastguard Worker       if (!xps_factory) {
1453*3ac0a46fSAndroid Build Coastguard Worker         break;
1454*3ac0a46fSAndroid Build Coastguard Worker       }
1455*3ac0a46fSAndroid Build Coastguard Worker 
1456*3ac0a46fSAndroid Build Coastguard Worker       std::unique_ptr<SkWStream> stream =
1457*3ac0a46fSAndroid Build Coastguard Worker           WriteToSkWStream(name(), page_index, "xps");
1458*3ac0a46fSAndroid Build Coastguard Worker       if (!stream) {
1459*3ac0a46fSAndroid Build Coastguard Worker         break;
1460*3ac0a46fSAndroid Build Coastguard Worker       }
1461*3ac0a46fSAndroid Build Coastguard Worker 
1462*3ac0a46fSAndroid Build Coastguard Worker       sk_sp<SkDocument> document =
1463*3ac0a46fSAndroid Build Coastguard Worker           SkXPS::MakeDocument(stream.get(), xps_factory);
1464*3ac0a46fSAndroid Build Coastguard Worker       if (!document) {
1465*3ac0a46fSAndroid Build Coastguard Worker         break;
1466*3ac0a46fSAndroid Build Coastguard Worker       }
1467*3ac0a46fSAndroid Build Coastguard Worker 
1468*3ac0a46fSAndroid Build Coastguard Worker       renderer = std::make_unique<SkDocumentPageRenderer>(
1469*3ac0a46fSAndroid Build Coastguard Worker           std::move(stream), std::move(document), page, width, height, flags);
1470*3ac0a46fSAndroid Build Coastguard Worker       break;
1471*3ac0a46fSAndroid Build Coastguard Worker     }
1472*3ac0a46fSAndroid Build Coastguard Worker #endif  // _WIN32
1473*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_SKIA
1474*3ac0a46fSAndroid Build Coastguard Worker 
1475*3ac0a46fSAndroid Build Coastguard Worker     default:
1476*3ac0a46fSAndroid Build Coastguard Worker       // Other formats won't write the output to a file, but still rasterize.
1477*3ac0a46fSAndroid Build Coastguard Worker       break;
1478*3ac0a46fSAndroid Build Coastguard Worker   }
1479*3ac0a46fSAndroid Build Coastguard Worker 
1480*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
1481*3ac0a46fSAndroid Build Coastguard Worker   if (!renderer && options().use_renderer_type == RendererType::kGdi) {
1482*3ac0a46fSAndroid Build Coastguard Worker     renderer = std::make_unique<GdiDisplayPageRenderer>(
1483*3ac0a46fSAndroid Build Coastguard Worker         page, /*width=*/width, /*height=*/height, /*flags=*/flags, idler(),
1484*3ac0a46fSAndroid Build Coastguard Worker         std::move(writer));
1485*3ac0a46fSAndroid Build Coastguard Worker   }
1486*3ac0a46fSAndroid Build Coastguard Worker #endif  // _WIN32
1487*3ac0a46fSAndroid Build Coastguard Worker 
1488*3ac0a46fSAndroid Build Coastguard Worker   if (!renderer) {
1489*3ac0a46fSAndroid Build Coastguard Worker     // Use a rasterizing page renderer by default.
1490*3ac0a46fSAndroid Build Coastguard Worker     if (options().render_oneshot) {
1491*3ac0a46fSAndroid Build Coastguard Worker       renderer = std::make_unique<OneShotBitmapPageRenderer>(
1492*3ac0a46fSAndroid Build Coastguard Worker           page, /*width=*/width, /*height=*/height, /*flags=*/flags, idler(),
1493*3ac0a46fSAndroid Build Coastguard Worker           std::move(writer));
1494*3ac0a46fSAndroid Build Coastguard Worker     } else {
1495*3ac0a46fSAndroid Build Coastguard Worker       // Client programs will be setting these values when rendering.
1496*3ac0a46fSAndroid Build Coastguard Worker       // This is a sample color scheme with distinct colors.
1497*3ac0a46fSAndroid Build Coastguard Worker       // Used only when `options().forced_color` is true.
1498*3ac0a46fSAndroid Build Coastguard Worker       FPDF_COLORSCHEME color_scheme;
1499*3ac0a46fSAndroid Build Coastguard Worker       color_scheme.path_fill_color = 0xFFFF0000;
1500*3ac0a46fSAndroid Build Coastguard Worker       color_scheme.path_stroke_color = 0xFF00FF00;
1501*3ac0a46fSAndroid Build Coastguard Worker       color_scheme.text_fill_color = 0xFF0000FF;
1502*3ac0a46fSAndroid Build Coastguard Worker       color_scheme.text_stroke_color = 0xFF00FFFF;
1503*3ac0a46fSAndroid Build Coastguard Worker 
1504*3ac0a46fSAndroid Build Coastguard Worker       renderer = std::make_unique<ProgressiveBitmapPageRenderer>(
1505*3ac0a46fSAndroid Build Coastguard Worker           page, /*width=*/width, /*height=*/height, /*flags=*/flags, idler(),
1506*3ac0a46fSAndroid Build Coastguard Worker           std::move(writer), options().forced_color ? &color_scheme : nullptr);
1507*3ac0a46fSAndroid Build Coastguard Worker     }
1508*3ac0a46fSAndroid Build Coastguard Worker   }
1509*3ac0a46fSAndroid Build Coastguard Worker 
1510*3ac0a46fSAndroid Build Coastguard Worker   if (renderer->Start()) {
1511*3ac0a46fSAndroid Build Coastguard Worker     while (renderer->Continue())
1512*3ac0a46fSAndroid Build Coastguard Worker       continue;
1513*3ac0a46fSAndroid Build Coastguard Worker     renderer->Finish(form());
1514*3ac0a46fSAndroid Build Coastguard Worker     renderer->Write(name(), page_index, /*md5=*/options().md5);
1515*3ac0a46fSAndroid Build Coastguard Worker   } else {
1516*3ac0a46fSAndroid Build Coastguard Worker     fprintf(stderr, "Page was too large to be rendered.\n");
1517*3ac0a46fSAndroid Build Coastguard Worker   }
1518*3ac0a46fSAndroid Build Coastguard Worker 
1519*3ac0a46fSAndroid Build Coastguard Worker   FORM_DoPageAAction(page, form(), FPDFPAGE_AACTION_CLOSE);
1520*3ac0a46fSAndroid Build Coastguard Worker   Idle();
1521*3ac0a46fSAndroid Build Coastguard Worker 
1522*3ac0a46fSAndroid Build Coastguard Worker   FORM_OnBeforeClosePage(page, form());
1523*3ac0a46fSAndroid Build Coastguard Worker   Idle();
1524*3ac0a46fSAndroid Build Coastguard Worker 
1525*3ac0a46fSAndroid Build Coastguard Worker   return renderer->HasOutput();
1526*3ac0a46fSAndroid Build Coastguard Worker }
1527*3ac0a46fSAndroid Build Coastguard Worker 
ProcessPdf(const std::string & name,const char * buf,size_t len,const std::string & events)1528*3ac0a46fSAndroid Build Coastguard Worker void Processor::ProcessPdf(const std::string& name,
1529*3ac0a46fSAndroid Build Coastguard Worker                            const char* buf,
1530*3ac0a46fSAndroid Build Coastguard Worker                            size_t len,
1531*3ac0a46fSAndroid Build Coastguard Worker                            const std::string& events) {
1532*3ac0a46fSAndroid Build Coastguard Worker   TestLoader loader({buf, len});
1533*3ac0a46fSAndroid Build Coastguard Worker 
1534*3ac0a46fSAndroid Build Coastguard Worker   FPDF_FILEACCESS file_access = {};
1535*3ac0a46fSAndroid Build Coastguard Worker   file_access.m_FileLen = static_cast<unsigned long>(len);
1536*3ac0a46fSAndroid Build Coastguard Worker   file_access.m_GetBlock = TestLoader::GetBlock;
1537*3ac0a46fSAndroid Build Coastguard Worker   file_access.m_Param = &loader;
1538*3ac0a46fSAndroid Build Coastguard Worker 
1539*3ac0a46fSAndroid Build Coastguard Worker   FX_FILEAVAIL file_avail = {};
1540*3ac0a46fSAndroid Build Coastguard Worker   file_avail.version = 1;
1541*3ac0a46fSAndroid Build Coastguard Worker   file_avail.IsDataAvail = Is_Data_Avail;
1542*3ac0a46fSAndroid Build Coastguard Worker 
1543*3ac0a46fSAndroid Build Coastguard Worker   FX_DOWNLOADHINTS hints = {};
1544*3ac0a46fSAndroid Build Coastguard Worker   hints.version = 1;
1545*3ac0a46fSAndroid Build Coastguard Worker   hints.AddSegment = Add_Segment;
1546*3ac0a46fSAndroid Build Coastguard Worker 
1547*3ac0a46fSAndroid Build Coastguard Worker   // |pdf_avail| must outlive |doc|.
1548*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFAvail pdf_avail(FPDFAvail_Create(&file_avail, &file_access));
1549*3ac0a46fSAndroid Build Coastguard Worker 
1550*3ac0a46fSAndroid Build Coastguard Worker   // |doc| must outlive |form_callbacks.loaded_pages|.
1551*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFDocument doc;
1552*3ac0a46fSAndroid Build Coastguard Worker 
1553*3ac0a46fSAndroid Build Coastguard Worker   const char* password =
1554*3ac0a46fSAndroid Build Coastguard Worker       options().password.empty() ? nullptr : options().password.c_str();
1555*3ac0a46fSAndroid Build Coastguard Worker   bool is_linearized = false;
1556*3ac0a46fSAndroid Build Coastguard Worker   if (options().use_load_mem_document) {
1557*3ac0a46fSAndroid Build Coastguard Worker     doc.reset(FPDF_LoadMemDocument(buf, len, password));
1558*3ac0a46fSAndroid Build Coastguard Worker   } else {
1559*3ac0a46fSAndroid Build Coastguard Worker     if (FPDFAvail_IsLinearized(pdf_avail.get()) == PDF_LINEARIZED) {
1560*3ac0a46fSAndroid Build Coastguard Worker       int avail_status = PDF_DATA_NOTAVAIL;
1561*3ac0a46fSAndroid Build Coastguard Worker       doc.reset(FPDFAvail_GetDocument(pdf_avail.get(), password));
1562*3ac0a46fSAndroid Build Coastguard Worker       if (doc) {
1563*3ac0a46fSAndroid Build Coastguard Worker         while (avail_status == PDF_DATA_NOTAVAIL)
1564*3ac0a46fSAndroid Build Coastguard Worker           avail_status = FPDFAvail_IsDocAvail(pdf_avail.get(), &hints);
1565*3ac0a46fSAndroid Build Coastguard Worker 
1566*3ac0a46fSAndroid Build Coastguard Worker         if (avail_status == PDF_DATA_ERROR) {
1567*3ac0a46fSAndroid Build Coastguard Worker           fprintf(stderr, "Unknown error in checking if doc was available.\n");
1568*3ac0a46fSAndroid Build Coastguard Worker           return;
1569*3ac0a46fSAndroid Build Coastguard Worker         }
1570*3ac0a46fSAndroid Build Coastguard Worker         avail_status = FPDFAvail_IsFormAvail(pdf_avail.get(), &hints);
1571*3ac0a46fSAndroid Build Coastguard Worker         if (avail_status == PDF_FORM_ERROR ||
1572*3ac0a46fSAndroid Build Coastguard Worker             avail_status == PDF_FORM_NOTAVAIL) {
1573*3ac0a46fSAndroid Build Coastguard Worker           fprintf(stderr,
1574*3ac0a46fSAndroid Build Coastguard Worker                   "Error %d was returned in checking if form was available.\n",
1575*3ac0a46fSAndroid Build Coastguard Worker                   avail_status);
1576*3ac0a46fSAndroid Build Coastguard Worker           return;
1577*3ac0a46fSAndroid Build Coastguard Worker         }
1578*3ac0a46fSAndroid Build Coastguard Worker         is_linearized = true;
1579*3ac0a46fSAndroid Build Coastguard Worker       }
1580*3ac0a46fSAndroid Build Coastguard Worker     } else {
1581*3ac0a46fSAndroid Build Coastguard Worker       doc.reset(FPDF_LoadCustomDocument(&file_access, password));
1582*3ac0a46fSAndroid Build Coastguard Worker     }
1583*3ac0a46fSAndroid Build Coastguard Worker   }
1584*3ac0a46fSAndroid Build Coastguard Worker 
1585*3ac0a46fSAndroid Build Coastguard Worker   if (!doc) {
1586*3ac0a46fSAndroid Build Coastguard Worker     PrintLastError();
1587*3ac0a46fSAndroid Build Coastguard Worker     return;
1588*3ac0a46fSAndroid Build Coastguard Worker   }
1589*3ac0a46fSAndroid Build Coastguard Worker 
1590*3ac0a46fSAndroid Build Coastguard Worker   if (!FPDF_DocumentHasValidCrossReferenceTable(doc.get()))
1591*3ac0a46fSAndroid Build Coastguard Worker     fprintf(stderr, "Document has invalid cross reference table\n");
1592*3ac0a46fSAndroid Build Coastguard Worker 
1593*3ac0a46fSAndroid Build Coastguard Worker   (void)FPDF_GetDocPermissions(doc.get());
1594*3ac0a46fSAndroid Build Coastguard Worker 
1595*3ac0a46fSAndroid Build Coastguard Worker   if (options().show_metadata) {
1596*3ac0a46fSAndroid Build Coastguard Worker     DumpMetaData(doc.get());
1597*3ac0a46fSAndroid Build Coastguard Worker   }
1598*3ac0a46fSAndroid Build Coastguard Worker 
1599*3ac0a46fSAndroid Build Coastguard Worker   if (options().save_attachments) {
1600*3ac0a46fSAndroid Build Coastguard Worker     WriteAttachments(doc.get(), name);
1601*3ac0a46fSAndroid Build Coastguard Worker   }
1602*3ac0a46fSAndroid Build Coastguard Worker 
1603*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_V8
1604*3ac0a46fSAndroid Build Coastguard Worker   IPDF_JSPLATFORM platform_callbacks = {};
1605*3ac0a46fSAndroid Build Coastguard Worker   platform_callbacks.version = 3;
1606*3ac0a46fSAndroid Build Coastguard Worker   platform_callbacks.app_alert = ExampleAppAlert;
1607*3ac0a46fSAndroid Build Coastguard Worker   platform_callbacks.app_beep = ExampleAppBeep;
1608*3ac0a46fSAndroid Build Coastguard Worker   platform_callbacks.app_response = ExampleAppResponse;
1609*3ac0a46fSAndroid Build Coastguard Worker   platform_callbacks.Doc_getFilePath = ExampleDocGetFilePath;
1610*3ac0a46fSAndroid Build Coastguard Worker   platform_callbacks.Doc_mail = ExampleDocMail;
1611*3ac0a46fSAndroid Build Coastguard Worker   platform_callbacks.Doc_print = ExampleDocPrint;
1612*3ac0a46fSAndroid Build Coastguard Worker   platform_callbacks.Doc_submitForm = ExampleDocSubmitForm;
1613*3ac0a46fSAndroid Build Coastguard Worker   platform_callbacks.Doc_gotoPage = ExampleDocGotoPage;
1614*3ac0a46fSAndroid Build Coastguard Worker   platform_callbacks.Field_browse = ExampleFieldBrowse;
1615*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_V8
1616*3ac0a46fSAndroid Build Coastguard Worker 
1617*3ac0a46fSAndroid Build Coastguard Worker   FPDF_FORMFILLINFO_PDFiumTest form_callbacks = {};
1618*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_XFA
1619*3ac0a46fSAndroid Build Coastguard Worker   form_callbacks.version = 2;
1620*3ac0a46fSAndroid Build Coastguard Worker   form_callbacks.xfa_disabled =
1621*3ac0a46fSAndroid Build Coastguard Worker       options().disable_xfa || options().disable_javascript;
1622*3ac0a46fSAndroid Build Coastguard Worker   form_callbacks.FFI_PopupMenu = ExamplePopupMenu;
1623*3ac0a46fSAndroid Build Coastguard Worker #else   // PDF_ENABLE_XFA
1624*3ac0a46fSAndroid Build Coastguard Worker   form_callbacks.version = 1;
1625*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_XFA
1626*3ac0a46fSAndroid Build Coastguard Worker   form_callbacks.FFI_ExecuteNamedAction = ExampleNamedAction;
1627*3ac0a46fSAndroid Build Coastguard Worker   form_callbacks.FFI_GetPage = GetPageForIndex;
1628*3ac0a46fSAndroid Build Coastguard Worker 
1629*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_V8
1630*3ac0a46fSAndroid Build Coastguard Worker   if (!options().disable_javascript) {
1631*3ac0a46fSAndroid Build Coastguard Worker     form_callbacks.m_pJsPlatform = &platform_callbacks;
1632*3ac0a46fSAndroid Build Coastguard Worker   }
1633*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_V8
1634*3ac0a46fSAndroid Build Coastguard Worker 
1635*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFFormHandle form(
1636*3ac0a46fSAndroid Build Coastguard Worker       FPDFDOC_InitFormFillEnvironment(doc.get(), &form_callbacks));
1637*3ac0a46fSAndroid Build Coastguard Worker   form_callbacks.form_handle = form.get();
1638*3ac0a46fSAndroid Build Coastguard Worker 
1639*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_XFA
1640*3ac0a46fSAndroid Build Coastguard Worker   if (!options().disable_xfa && !options().disable_javascript) {
1641*3ac0a46fSAndroid Build Coastguard Worker     int doc_type = FPDF_GetFormType(doc.get());
1642*3ac0a46fSAndroid Build Coastguard Worker     if (doc_type == FORMTYPE_XFA_FULL || doc_type == FORMTYPE_XFA_FOREGROUND) {
1643*3ac0a46fSAndroid Build Coastguard Worker       if (!FPDF_LoadXFA(doc.get()))
1644*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "LoadXFA unsuccessful, continuing anyway.\n");
1645*3ac0a46fSAndroid Build Coastguard Worker     }
1646*3ac0a46fSAndroid Build Coastguard Worker   }
1647*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_XFA
1648*3ac0a46fSAndroid Build Coastguard Worker 
1649*3ac0a46fSAndroid Build Coastguard Worker   FPDF_SetFormFieldHighlightColor(form.get(), FPDF_FORMFIELD_UNKNOWN, 0xFFE4DD);
1650*3ac0a46fSAndroid Build Coastguard Worker   FPDF_SetFormFieldHighlightAlpha(form.get(), 100);
1651*3ac0a46fSAndroid Build Coastguard Worker   FORM_DoDocumentJSAction(form.get());
1652*3ac0a46fSAndroid Build Coastguard Worker   FORM_DoDocumentOpenAction(form.get());
1653*3ac0a46fSAndroid Build Coastguard Worker 
1654*3ac0a46fSAndroid Build Coastguard Worker #if _WIN32
1655*3ac0a46fSAndroid Build Coastguard Worker   if (options().output_format == OutputFormat::kPs2) {
1656*3ac0a46fSAndroid Build Coastguard Worker     FPDF_SetPrintMode(FPDF_PRINTMODE_POSTSCRIPT2);
1657*3ac0a46fSAndroid Build Coastguard Worker   } else if (options().output_format == OutputFormat::kPs3) {
1658*3ac0a46fSAndroid Build Coastguard Worker     FPDF_SetPrintMode(FPDF_PRINTMODE_POSTSCRIPT3);
1659*3ac0a46fSAndroid Build Coastguard Worker   } else if (options().output_format == OutputFormat::kPs3Type42) {
1660*3ac0a46fSAndroid Build Coastguard Worker     FPDF_SetPrintMode(FPDF_PRINTMODE_POSTSCRIPT3_TYPE42);
1661*3ac0a46fSAndroid Build Coastguard Worker   }
1662*3ac0a46fSAndroid Build Coastguard Worker #endif
1663*3ac0a46fSAndroid Build Coastguard Worker 
1664*3ac0a46fSAndroid Build Coastguard Worker   int page_count = FPDF_GetPageCount(doc.get());
1665*3ac0a46fSAndroid Build Coastguard Worker   int processed_pages = 0;
1666*3ac0a46fSAndroid Build Coastguard Worker   int bad_pages = 0;
1667*3ac0a46fSAndroid Build Coastguard Worker   int first_page = options().pages ? options().first_page : 0;
1668*3ac0a46fSAndroid Build Coastguard Worker   int last_page = options().pages ? options().last_page + 1 : page_count;
1669*3ac0a46fSAndroid Build Coastguard Worker   PdfProcessor pdf_processor(this, &name, &events, doc.get(), form.get(),
1670*3ac0a46fSAndroid Build Coastguard Worker                              &form_callbacks);
1671*3ac0a46fSAndroid Build Coastguard Worker   for (int i = first_page; i < last_page; ++i) {
1672*3ac0a46fSAndroid Build Coastguard Worker     if (is_linearized) {
1673*3ac0a46fSAndroid Build Coastguard Worker       int avail_status = PDF_DATA_NOTAVAIL;
1674*3ac0a46fSAndroid Build Coastguard Worker       while (avail_status == PDF_DATA_NOTAVAIL)
1675*3ac0a46fSAndroid Build Coastguard Worker         avail_status = FPDFAvail_IsPageAvail(pdf_avail.get(), i, &hints);
1676*3ac0a46fSAndroid Build Coastguard Worker 
1677*3ac0a46fSAndroid Build Coastguard Worker       if (avail_status == PDF_DATA_ERROR) {
1678*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Unknown error in checking if page %d is available.\n",
1679*3ac0a46fSAndroid Build Coastguard Worker                 i);
1680*3ac0a46fSAndroid Build Coastguard Worker         return;
1681*3ac0a46fSAndroid Build Coastguard Worker       }
1682*3ac0a46fSAndroid Build Coastguard Worker     }
1683*3ac0a46fSAndroid Build Coastguard Worker     if (pdf_processor.ProcessPage(i)) {
1684*3ac0a46fSAndroid Build Coastguard Worker       ++processed_pages;
1685*3ac0a46fSAndroid Build Coastguard Worker     } else {
1686*3ac0a46fSAndroid Build Coastguard Worker       ++bad_pages;
1687*3ac0a46fSAndroid Build Coastguard Worker     }
1688*3ac0a46fSAndroid Build Coastguard Worker     Idle();
1689*3ac0a46fSAndroid Build Coastguard Worker   }
1690*3ac0a46fSAndroid Build Coastguard Worker 
1691*3ac0a46fSAndroid Build Coastguard Worker   FORM_DoDocumentAAction(form.get(), FPDFDOC_AACTION_WC);
1692*3ac0a46fSAndroid Build Coastguard Worker   Idle();
1693*3ac0a46fSAndroid Build Coastguard Worker 
1694*3ac0a46fSAndroid Build Coastguard Worker   fprintf(stderr, "Processed %d pages.\n", processed_pages);
1695*3ac0a46fSAndroid Build Coastguard Worker   if (bad_pages)
1696*3ac0a46fSAndroid Build Coastguard Worker     fprintf(stderr, "Skipped %d bad pages.\n", bad_pages);
1697*3ac0a46fSAndroid Build Coastguard Worker }
1698*3ac0a46fSAndroid Build Coastguard Worker 
ShowConfig()1699*3ac0a46fSAndroid Build Coastguard Worker void ShowConfig() {
1700*3ac0a46fSAndroid Build Coastguard Worker   std::string config;
1701*3ac0a46fSAndroid Build Coastguard Worker   [[maybe_unused]] auto append_config = [&config](const char* name) {
1702*3ac0a46fSAndroid Build Coastguard Worker     if (!config.empty())
1703*3ac0a46fSAndroid Build Coastguard Worker       config += ',';
1704*3ac0a46fSAndroid Build Coastguard Worker     config += name;
1705*3ac0a46fSAndroid Build Coastguard Worker   };
1706*3ac0a46fSAndroid Build Coastguard Worker 
1707*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_V8
1708*3ac0a46fSAndroid Build Coastguard Worker   append_config("V8");
1709*3ac0a46fSAndroid Build Coastguard Worker #endif
1710*3ac0a46fSAndroid Build Coastguard Worker #ifdef V8_USE_EXTERNAL_STARTUP_DATA
1711*3ac0a46fSAndroid Build Coastguard Worker   append_config("V8_EXTERNAL");
1712*3ac0a46fSAndroid Build Coastguard Worker #endif
1713*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_XFA
1714*3ac0a46fSAndroid Build Coastguard Worker   append_config("XFA");
1715*3ac0a46fSAndroid Build Coastguard Worker #endif
1716*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_ASAN
1717*3ac0a46fSAndroid Build Coastguard Worker   append_config("ASAN");
1718*3ac0a46fSAndroid Build Coastguard Worker #endif
1719*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_SKIA
1720*3ac0a46fSAndroid Build Coastguard Worker   append_config("SKIA");
1721*3ac0a46fSAndroid Build Coastguard Worker #endif
1722*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
1723*3ac0a46fSAndroid Build Coastguard Worker   append_config("GDI");
1724*3ac0a46fSAndroid Build Coastguard Worker #endif
1725*3ac0a46fSAndroid Build Coastguard Worker   printf("%s\n", config.c_str());
1726*3ac0a46fSAndroid Build Coastguard Worker }
1727*3ac0a46fSAndroid Build Coastguard Worker 
1728*3ac0a46fSAndroid Build Coastguard Worker constexpr char kUsageString[] =
1729*3ac0a46fSAndroid Build Coastguard Worker     "Usage: pdfium_test [OPTION] [FILE]...\n"
1730*3ac0a46fSAndroid Build Coastguard Worker     "  --show-config          - print build options and exit\n"
1731*3ac0a46fSAndroid Build Coastguard Worker     "  --show-metadata        - print the file metadata\n"
1732*3ac0a46fSAndroid Build Coastguard Worker     "  --show-pageinfo        - print information about pages\n"
1733*3ac0a46fSAndroid Build Coastguard Worker     "  --show-structure       - print the structure elements from the "
1734*3ac0a46fSAndroid Build Coastguard Worker     "document\n"
1735*3ac0a46fSAndroid Build Coastguard Worker     "  --send-events          - send input described by .evt file\n"
1736*3ac0a46fSAndroid Build Coastguard Worker     "  --mem-document         - load document with FPDF_LoadMemDocument()\n"
1737*3ac0a46fSAndroid Build Coastguard Worker     "  --render-oneshot       - render image without using progressive "
1738*3ac0a46fSAndroid Build Coastguard Worker     "renderer\n"
1739*3ac0a46fSAndroid Build Coastguard Worker     "  --lcd-text             - render text optimized for LCD displays\n"
1740*3ac0a46fSAndroid Build Coastguard Worker     "  --no-nativetext        - render without using the native text output\n"
1741*3ac0a46fSAndroid Build Coastguard Worker     "  --grayscale            - render grayscale output\n"
1742*3ac0a46fSAndroid Build Coastguard Worker     "  --forced-color         - render in forced color mode\n"
1743*3ac0a46fSAndroid Build Coastguard Worker     "  --fill-to-stroke       - render fill as stroke in forced color mode\n"
1744*3ac0a46fSAndroid Build Coastguard Worker     "  --limit-cache          - render limiting image cache size\n"
1745*3ac0a46fSAndroid Build Coastguard Worker     "  --force-halftone       - render forcing halftone\n"
1746*3ac0a46fSAndroid Build Coastguard Worker     "  --printing             - render as if for printing\n"
1747*3ac0a46fSAndroid Build Coastguard Worker     "  --no-smoothtext        - render disabling text anti-aliasing\n"
1748*3ac0a46fSAndroid Build Coastguard Worker     "  --no-smoothimage       - render disabling image anti-alisasing\n"
1749*3ac0a46fSAndroid Build Coastguard Worker     "  --no-smoothpath        - render disabling path anti-aliasing\n"
1750*3ac0a46fSAndroid Build Coastguard Worker     "  --reverse-byte-order   - render to BGRA, if supported by the output "
1751*3ac0a46fSAndroid Build Coastguard Worker     "format\n"
1752*3ac0a46fSAndroid Build Coastguard Worker     "  --save-attachments     - write embedded attachments "
1753*3ac0a46fSAndroid Build Coastguard Worker     "<pdf-name>.attachment.<attachment-name>\n"
1754*3ac0a46fSAndroid Build Coastguard Worker     "  --save-images          - write raw embedded images "
1755*3ac0a46fSAndroid Build Coastguard Worker     "<pdf-name>.<page-number>.<object-number>.png\n"
1756*3ac0a46fSAndroid Build Coastguard Worker     "  --save-rendered-images - write embedded images as rendered on the page "
1757*3ac0a46fSAndroid Build Coastguard Worker     "<pdf-name>.<page-number>.<object-number>.png\n"
1758*3ac0a46fSAndroid Build Coastguard Worker     "  --save-thumbs          - write page thumbnails "
1759*3ac0a46fSAndroid Build Coastguard Worker     "<pdf-name>.thumbnail.<page-number>.png\n"
1760*3ac0a46fSAndroid Build Coastguard Worker     "  --save-thumbs-dec      - write page thumbnails' decoded stream data"
1761*3ac0a46fSAndroid Build Coastguard Worker     "<pdf-name>.thumbnail.decoded.<page-number>.png\n"
1762*3ac0a46fSAndroid Build Coastguard Worker     "  --save-thumbs-raw      - write page thumbnails' raw stream data"
1763*3ac0a46fSAndroid Build Coastguard Worker     "<pdf-name>.thumbnail.raw.<page-number>.png\n"
1764*3ac0a46fSAndroid Build Coastguard Worker 
1765*3ac0a46fSAndroid Build Coastguard Worker #if defined(PDF_ENABLE_SKIA)
1766*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
1767*3ac0a46fSAndroid Build Coastguard Worker     "  --use-renderer         - renderer to use, one of [agg | gdi | skia]\n"
1768*3ac0a46fSAndroid Build Coastguard Worker #else
1769*3ac0a46fSAndroid Build Coastguard Worker     "  --use-renderer         - renderer to use, one of [agg | skia]\n"
1770*3ac0a46fSAndroid Build Coastguard Worker #endif  // _WIN32
1771*3ac0a46fSAndroid Build Coastguard Worker #else
1772*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
1773*3ac0a46fSAndroid Build Coastguard Worker     "  --use-renderer         - renderer to use, one of [agg | gdi]\n"
1774*3ac0a46fSAndroid Build Coastguard Worker #else
1775*3ac0a46fSAndroid Build Coastguard Worker     "  --use-renderer         - renderer to use, one of [agg]\n"
1776*3ac0a46fSAndroid Build Coastguard Worker #endif  // _WIN32
1777*3ac0a46fSAndroid Build Coastguard Worker #endif  // defined(PDF_ENABLE_SKIA)
1778*3ac0a46fSAndroid Build Coastguard Worker 
1779*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_V8
1780*3ac0a46fSAndroid Build Coastguard Worker     "  --disable-javascript   - do not execute JS in PDF files\n"
1781*3ac0a46fSAndroid Build Coastguard Worker     "  --js-flags=<flags>     - additional flags to pass to V8\n"
1782*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_XFA
1783*3ac0a46fSAndroid Build Coastguard Worker     "  --disable-xfa          - do not process XFA forms\n"
1784*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_XFA
1785*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_V8
1786*3ac0a46fSAndroid Build Coastguard Worker #ifdef ENABLE_CALLGRIND
1787*3ac0a46fSAndroid Build Coastguard Worker     "  --callgrind-delim      - delimit interesting section when using "
1788*3ac0a46fSAndroid Build Coastguard Worker     "callgrind\n"
1789*3ac0a46fSAndroid Build Coastguard Worker #endif
1790*3ac0a46fSAndroid Build Coastguard Worker #if defined(__APPLE__) || (defined(__linux__) && !defined(__ANDROID__))
1791*3ac0a46fSAndroid Build Coastguard Worker     "  --no-system-fonts      - do not use system fonts, overrides --font-dir\n"
1792*3ac0a46fSAndroid Build Coastguard Worker #endif
1793*3ac0a46fSAndroid Build Coastguard Worker     "  --croscore-font-names  - use Croscore font names\n"
1794*3ac0a46fSAndroid Build Coastguard Worker     "  --bin-dir=<path>       - override path to v8 external data\n"
1795*3ac0a46fSAndroid Build Coastguard Worker     "  --font-dir=<path>      - override path to external fonts\n"
1796*3ac0a46fSAndroid Build Coastguard Worker     "  --scale=<number>       - scale output size by number (e.g. 0.5)\n"
1797*3ac0a46fSAndroid Build Coastguard Worker     "  --password=<secret>    - password to decrypt the PDF with\n"
1798*3ac0a46fSAndroid Build Coastguard Worker     "  --pages=<number>(-<number>) - only render the given 0-based page(s)\n"
1799*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
1800*3ac0a46fSAndroid Build Coastguard Worker     "  --bmp   - write page images <pdf-name>.<page-number>.bmp\n"
1801*3ac0a46fSAndroid Build Coastguard Worker     "  --emf   - write page meta files <pdf-name>.<page-number>.emf\n"
1802*3ac0a46fSAndroid Build Coastguard Worker     "  --ps2   - write page raw PostScript (Lvl 2) "
1803*3ac0a46fSAndroid Build Coastguard Worker     "<pdf-name>.<page-number>.ps\n"
1804*3ac0a46fSAndroid Build Coastguard Worker     "  --ps3   - write page raw PostScript (Lvl 3) "
1805*3ac0a46fSAndroid Build Coastguard Worker     "<pdf-name>.<page-number>.ps\n"
1806*3ac0a46fSAndroid Build Coastguard Worker     "  --ps3-type42 - write page raw PostScript (Lvl 3 with Type 42 fonts) "
1807*3ac0a46fSAndroid Build Coastguard Worker     "<pdf-name>.<page-number>.ps\n"
1808*3ac0a46fSAndroid Build Coastguard Worker #endif
1809*3ac0a46fSAndroid Build Coastguard Worker     "  --txt   - write page text in UTF32-LE <pdf-name>.<page-number>.txt\n"
1810*3ac0a46fSAndroid Build Coastguard Worker     "  --png   - write page images <pdf-name>.<page-number>.png\n"
1811*3ac0a46fSAndroid Build Coastguard Worker     "  --ppm   - write page images <pdf-name>.<page-number>.ppm\n"
1812*3ac0a46fSAndroid Build Coastguard Worker     "  --annot - write annotation info <pdf-name>.<page-number>.annot.txt\n"
1813*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_SKIA
1814*3ac0a46fSAndroid Build Coastguard Worker     "  --skp   - write page images <pdf-name>.<page-number>.skp\n"
1815*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
1816*3ac0a46fSAndroid Build Coastguard Worker     "  --xps   - write page images <pdf-name>.<page-number>.xps\n"
1817*3ac0a46fSAndroid Build Coastguard Worker #endif  // _WIN32
1818*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_SKIA
1819*3ac0a46fSAndroid Build Coastguard Worker     "  --md5   - write output image paths and their md5 hashes to stdout.\n"
1820*3ac0a46fSAndroid Build Coastguard Worker     "  --time=<number> - Seconds since the epoch to set system time.\n"
1821*3ac0a46fSAndroid Build Coastguard Worker     "";
1822*3ac0a46fSAndroid Build Coastguard Worker 
SetUpErrorHandling()1823*3ac0a46fSAndroid Build Coastguard Worker void SetUpErrorHandling() {
1824*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
1825*3ac0a46fSAndroid Build Coastguard Worker   // Suppress various Windows error reporting mechanisms that can pop up dialog
1826*3ac0a46fSAndroid Build Coastguard Worker   // boxes and cause the program to hang.
1827*3ac0a46fSAndroid Build Coastguard Worker   SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
1828*3ac0a46fSAndroid Build Coastguard Worker                SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
1829*3ac0a46fSAndroid Build Coastguard Worker   _set_error_mode(_OUT_TO_STDERR);
1830*3ac0a46fSAndroid Build Coastguard Worker   _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
1831*3ac0a46fSAndroid Build Coastguard Worker   _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
1832*3ac0a46fSAndroid Build Coastguard Worker   _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
1833*3ac0a46fSAndroid Build Coastguard Worker #endif  // _WIN32
1834*3ac0a46fSAndroid Build Coastguard Worker }
1835*3ac0a46fSAndroid Build Coastguard Worker 
1836*3ac0a46fSAndroid Build Coastguard Worker }  // namespace
1837*3ac0a46fSAndroid Build Coastguard Worker 
main(int argc,const char * argv[])1838*3ac0a46fSAndroid Build Coastguard Worker int main(int argc, const char* argv[]) {
1839*3ac0a46fSAndroid Build Coastguard Worker #if defined(PDF_USE_PARTITION_ALLOC)
1840*3ac0a46fSAndroid Build Coastguard Worker   pdfium::ConfigurePartitionAllocShimPartitionForTest();
1841*3ac0a46fSAndroid Build Coastguard Worker #endif
1842*3ac0a46fSAndroid Build Coastguard Worker 
1843*3ac0a46fSAndroid Build Coastguard Worker   SetUpErrorHandling();
1844*3ac0a46fSAndroid Build Coastguard Worker   setlocale(LC_CTYPE, "en_US.UTF-8");  // For printf() of high-characters.
1845*3ac0a46fSAndroid Build Coastguard Worker 
1846*3ac0a46fSAndroid Build Coastguard Worker   std::vector<std::string> args(argv, argv + argc);
1847*3ac0a46fSAndroid Build Coastguard Worker   Options options;
1848*3ac0a46fSAndroid Build Coastguard Worker   std::vector<std::string> files;
1849*3ac0a46fSAndroid Build Coastguard Worker   if (!ParseCommandLine(args, &options, &files)) {
1850*3ac0a46fSAndroid Build Coastguard Worker     fprintf(stderr, "%s", kUsageString);
1851*3ac0a46fSAndroid Build Coastguard Worker     return 1;
1852*3ac0a46fSAndroid Build Coastguard Worker   }
1853*3ac0a46fSAndroid Build Coastguard Worker 
1854*3ac0a46fSAndroid Build Coastguard Worker   if (options.show_config) {
1855*3ac0a46fSAndroid Build Coastguard Worker     ShowConfig();
1856*3ac0a46fSAndroid Build Coastguard Worker     return 0;
1857*3ac0a46fSAndroid Build Coastguard Worker   }
1858*3ac0a46fSAndroid Build Coastguard Worker 
1859*3ac0a46fSAndroid Build Coastguard Worker   if (files.empty()) {
1860*3ac0a46fSAndroid Build Coastguard Worker     fprintf(stderr, "No input files.\n");
1861*3ac0a46fSAndroid Build Coastguard Worker     return 1;
1862*3ac0a46fSAndroid Build Coastguard Worker   }
1863*3ac0a46fSAndroid Build Coastguard Worker 
1864*3ac0a46fSAndroid Build Coastguard Worker   FPDF_LIBRARY_CONFIG config;
1865*3ac0a46fSAndroid Build Coastguard Worker   config.version = 4;
1866*3ac0a46fSAndroid Build Coastguard Worker   config.m_pUserFontPaths = nullptr;
1867*3ac0a46fSAndroid Build Coastguard Worker   config.m_pIsolate = nullptr;
1868*3ac0a46fSAndroid Build Coastguard Worker   config.m_v8EmbedderSlot = 0;
1869*3ac0a46fSAndroid Build Coastguard Worker   config.m_pPlatform = nullptr;
1870*3ac0a46fSAndroid Build Coastguard Worker 
1871*3ac0a46fSAndroid Build Coastguard Worker   switch (options.use_renderer_type) {
1872*3ac0a46fSAndroid Build Coastguard Worker     case RendererType::kDefault:
1873*3ac0a46fSAndroid Build Coastguard Worker       config.m_RendererType = GetDefaultRendererType();
1874*3ac0a46fSAndroid Build Coastguard Worker       break;
1875*3ac0a46fSAndroid Build Coastguard Worker 
1876*3ac0a46fSAndroid Build Coastguard Worker     case RendererType::kAgg:
1877*3ac0a46fSAndroid Build Coastguard Worker       config.m_RendererType = FPDF_RENDERERTYPE_AGG;
1878*3ac0a46fSAndroid Build Coastguard Worker       break;
1879*3ac0a46fSAndroid Build Coastguard Worker 
1880*3ac0a46fSAndroid Build Coastguard Worker #ifdef _WIN32
1881*3ac0a46fSAndroid Build Coastguard Worker     case RendererType::kGdi:
1882*3ac0a46fSAndroid Build Coastguard Worker       // GDI renderer uses `FPDF_RenderPage()`, rather than a renderer type.
1883*3ac0a46fSAndroid Build Coastguard Worker       config.m_RendererType = GetDefaultRendererType();
1884*3ac0a46fSAndroid Build Coastguard Worker       break;
1885*3ac0a46fSAndroid Build Coastguard Worker #endif  // _WIN32
1886*3ac0a46fSAndroid Build Coastguard Worker 
1887*3ac0a46fSAndroid Build Coastguard Worker #if defined(PDF_ENABLE_SKIA)
1888*3ac0a46fSAndroid Build Coastguard Worker     case RendererType::kSkia:
1889*3ac0a46fSAndroid Build Coastguard Worker #if defined(BUILD_WITH_CHROMIUM)
1890*3ac0a46fSAndroid Build Coastguard Worker       // Needed to support Chromium's copy of Skia, which uses a
1891*3ac0a46fSAndroid Build Coastguard Worker       // `DiscardableMemoryAllocator`.
1892*3ac0a46fSAndroid Build Coastguard Worker       chromium_support::InitializeDiscardableMemoryAllocator();
1893*3ac0a46fSAndroid Build Coastguard Worker #endif  // defined(BUILD_WITH_CHROMIUM)
1894*3ac0a46fSAndroid Build Coastguard Worker       config.m_RendererType = FPDF_RENDERERTYPE_SKIA;
1895*3ac0a46fSAndroid Build Coastguard Worker       break;
1896*3ac0a46fSAndroid Build Coastguard Worker #endif  // defined(PDF_ENABLE_SKIA)
1897*3ac0a46fSAndroid Build Coastguard Worker   }
1898*3ac0a46fSAndroid Build Coastguard Worker 
1899*3ac0a46fSAndroid Build Coastguard Worker   std::function<void()> idler = []() {};
1900*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_V8
1901*3ac0a46fSAndroid Build Coastguard Worker #ifdef V8_USE_EXTERNAL_STARTUP_DATA
1902*3ac0a46fSAndroid Build Coastguard Worker   v8::StartupData snapshot;
1903*3ac0a46fSAndroid Build Coastguard Worker #endif  // V8_USE_EXTERNAL_STARTUP_DATA
1904*3ac0a46fSAndroid Build Coastguard Worker   std::unique_ptr<v8::Platform> platform;
1905*3ac0a46fSAndroid Build Coastguard Worker   std::unique_ptr<v8::Isolate, V8IsolateDeleter> isolate;
1906*3ac0a46fSAndroid Build Coastguard Worker   if (!options.disable_javascript) {
1907*3ac0a46fSAndroid Build Coastguard Worker #ifdef V8_USE_EXTERNAL_STARTUP_DATA
1908*3ac0a46fSAndroid Build Coastguard Worker     platform = InitializeV8ForPDFiumWithStartupData(
1909*3ac0a46fSAndroid Build Coastguard Worker         options.exe_path, options.js_flags, options.bin_directory, &snapshot);
1910*3ac0a46fSAndroid Build Coastguard Worker #else   // V8_USE_EXTERNAL_STARTUP_DATA
1911*3ac0a46fSAndroid Build Coastguard Worker     platform = InitializeV8ForPDFium(options.exe_path, options.js_flags);
1912*3ac0a46fSAndroid Build Coastguard Worker #endif  // V8_USE_EXTERNAL_STARTUP_DATA
1913*3ac0a46fSAndroid Build Coastguard Worker     if (!platform) {
1914*3ac0a46fSAndroid Build Coastguard Worker       fprintf(stderr, "V8 initialization failed.\n");
1915*3ac0a46fSAndroid Build Coastguard Worker       return 1;
1916*3ac0a46fSAndroid Build Coastguard Worker     }
1917*3ac0a46fSAndroid Build Coastguard Worker     config.m_pPlatform = platform.get();
1918*3ac0a46fSAndroid Build Coastguard Worker 
1919*3ac0a46fSAndroid Build Coastguard Worker     v8::Isolate::CreateParams params;
1920*3ac0a46fSAndroid Build Coastguard Worker     params.array_buffer_allocator = static_cast<v8::ArrayBuffer::Allocator*>(
1921*3ac0a46fSAndroid Build Coastguard Worker         FPDF_GetArrayBufferAllocatorSharedInstance());
1922*3ac0a46fSAndroid Build Coastguard Worker     isolate.reset(v8::Isolate::New(params));
1923*3ac0a46fSAndroid Build Coastguard Worker     config.m_pIsolate = isolate.get();
1924*3ac0a46fSAndroid Build Coastguard Worker 
1925*3ac0a46fSAndroid Build Coastguard Worker     idler = [&platform, &isolate]() {
1926*3ac0a46fSAndroid Build Coastguard Worker       int task_count = 0;
1927*3ac0a46fSAndroid Build Coastguard Worker       while (v8::platform::PumpMessageLoop(platform.get(), isolate.get()))
1928*3ac0a46fSAndroid Build Coastguard Worker         ++task_count;
1929*3ac0a46fSAndroid Build Coastguard Worker       if (task_count)
1930*3ac0a46fSAndroid Build Coastguard Worker         fprintf(stderr, "Pumped %d tasks\n", task_count);
1931*3ac0a46fSAndroid Build Coastguard Worker     };
1932*3ac0a46fSAndroid Build Coastguard Worker   }
1933*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_V8
1934*3ac0a46fSAndroid Build Coastguard Worker 
1935*3ac0a46fSAndroid Build Coastguard Worker   const char* path_array[2] = {nullptr, nullptr};
1936*3ac0a46fSAndroid Build Coastguard Worker   absl::optional<const char*> custom_font_path = GetCustomFontPath(options);
1937*3ac0a46fSAndroid Build Coastguard Worker   if (custom_font_path.has_value()) {
1938*3ac0a46fSAndroid Build Coastguard Worker     path_array[0] = custom_font_path.value();
1939*3ac0a46fSAndroid Build Coastguard Worker     config.m_pUserFontPaths = path_array;
1940*3ac0a46fSAndroid Build Coastguard Worker   }
1941*3ac0a46fSAndroid Build Coastguard Worker 
1942*3ac0a46fSAndroid Build Coastguard Worker   FPDF_InitLibraryWithConfig(&config);
1943*3ac0a46fSAndroid Build Coastguard Worker 
1944*3ac0a46fSAndroid Build Coastguard Worker   std::unique_ptr<FontRenamer> font_renamer;
1945*3ac0a46fSAndroid Build Coastguard Worker   if (options.croscore_font_names)
1946*3ac0a46fSAndroid Build Coastguard Worker     font_renamer = std::make_unique<FontRenamer>();
1947*3ac0a46fSAndroid Build Coastguard Worker 
1948*3ac0a46fSAndroid Build Coastguard Worker   UNSUPPORT_INFO unsupported_info = {};
1949*3ac0a46fSAndroid Build Coastguard Worker   unsupported_info.version = 1;
1950*3ac0a46fSAndroid Build Coastguard Worker   unsupported_info.FSDK_UnSupport_Handler = ExampleUnsupportedHandler;
1951*3ac0a46fSAndroid Build Coastguard Worker 
1952*3ac0a46fSAndroid Build Coastguard Worker   FSDK_SetUnSpObjProcessHandler(&unsupported_info);
1953*3ac0a46fSAndroid Build Coastguard Worker 
1954*3ac0a46fSAndroid Build Coastguard Worker   if (options.time > -1) {
1955*3ac0a46fSAndroid Build Coastguard Worker     // This must be a static var to avoid explicit capture, so the lambda can be
1956*3ac0a46fSAndroid Build Coastguard Worker     // converted to a function ptr.
1957*3ac0a46fSAndroid Build Coastguard Worker     static time_t time_ret = options.time;
1958*3ac0a46fSAndroid Build Coastguard Worker     FSDK_SetTimeFunction([]() { return time_ret; });
1959*3ac0a46fSAndroid Build Coastguard Worker     FSDK_SetLocaltimeFunction([](const time_t* tp) { return gmtime(tp); });
1960*3ac0a46fSAndroid Build Coastguard Worker   }
1961*3ac0a46fSAndroid Build Coastguard Worker 
1962*3ac0a46fSAndroid Build Coastguard Worker   Processor processor(&options, &idler);
1963*3ac0a46fSAndroid Build Coastguard Worker   for (const std::string& filename : files) {
1964*3ac0a46fSAndroid Build Coastguard Worker     size_t file_length = 0;
1965*3ac0a46fSAndroid Build Coastguard Worker     std::unique_ptr<char, pdfium::FreeDeleter> file_contents =
1966*3ac0a46fSAndroid Build Coastguard Worker         GetFileContents(filename.c_str(), &file_length);
1967*3ac0a46fSAndroid Build Coastguard Worker     if (!file_contents)
1968*3ac0a46fSAndroid Build Coastguard Worker       continue;
1969*3ac0a46fSAndroid Build Coastguard Worker     fprintf(stderr, "Processing PDF file %s.\n", filename.c_str());
1970*3ac0a46fSAndroid Build Coastguard Worker 
1971*3ac0a46fSAndroid Build Coastguard Worker #ifdef ENABLE_CALLGRIND
1972*3ac0a46fSAndroid Build Coastguard Worker     if (options.callgrind_delimiters)
1973*3ac0a46fSAndroid Build Coastguard Worker       CALLGRIND_START_INSTRUMENTATION;
1974*3ac0a46fSAndroid Build Coastguard Worker #endif  // ENABLE_CALLGRIND
1975*3ac0a46fSAndroid Build Coastguard Worker 
1976*3ac0a46fSAndroid Build Coastguard Worker     std::string events;
1977*3ac0a46fSAndroid Build Coastguard Worker     if (options.send_events) {
1978*3ac0a46fSAndroid Build Coastguard Worker       std::string event_filename = filename;
1979*3ac0a46fSAndroid Build Coastguard Worker       size_t event_length = 0;
1980*3ac0a46fSAndroid Build Coastguard Worker       size_t extension_pos = event_filename.find(".pdf");
1981*3ac0a46fSAndroid Build Coastguard Worker       if (extension_pos != std::string::npos) {
1982*3ac0a46fSAndroid Build Coastguard Worker         event_filename.replace(extension_pos, 4, ".evt");
1983*3ac0a46fSAndroid Build Coastguard Worker         if (access(event_filename.c_str(), R_OK) == 0) {
1984*3ac0a46fSAndroid Build Coastguard Worker           fprintf(stderr, "Using event file %s.\n", event_filename.c_str());
1985*3ac0a46fSAndroid Build Coastguard Worker           std::unique_ptr<char, pdfium::FreeDeleter> event_contents =
1986*3ac0a46fSAndroid Build Coastguard Worker               GetFileContents(event_filename.c_str(), &event_length);
1987*3ac0a46fSAndroid Build Coastguard Worker           if (event_contents) {
1988*3ac0a46fSAndroid Build Coastguard Worker             fprintf(stderr, "Sending events from: %s\n",
1989*3ac0a46fSAndroid Build Coastguard Worker                     event_filename.c_str());
1990*3ac0a46fSAndroid Build Coastguard Worker             events = std::string(event_contents.get(), event_length);
1991*3ac0a46fSAndroid Build Coastguard Worker           }
1992*3ac0a46fSAndroid Build Coastguard Worker         }
1993*3ac0a46fSAndroid Build Coastguard Worker       }
1994*3ac0a46fSAndroid Build Coastguard Worker     }
1995*3ac0a46fSAndroid Build Coastguard Worker 
1996*3ac0a46fSAndroid Build Coastguard Worker     processor.ProcessPdf(filename, file_contents.get(), file_length, events);
1997*3ac0a46fSAndroid Build Coastguard Worker 
1998*3ac0a46fSAndroid Build Coastguard Worker #ifdef ENABLE_CALLGRIND
1999*3ac0a46fSAndroid Build Coastguard Worker     if (options.callgrind_delimiters)
2000*3ac0a46fSAndroid Build Coastguard Worker       CALLGRIND_STOP_INSTRUMENTATION;
2001*3ac0a46fSAndroid Build Coastguard Worker #endif  // ENABLE_CALLGRIND
2002*3ac0a46fSAndroid Build Coastguard Worker   }
2003*3ac0a46fSAndroid Build Coastguard Worker 
2004*3ac0a46fSAndroid Build Coastguard Worker   FPDF_DestroyLibrary();
2005*3ac0a46fSAndroid Build Coastguard Worker 
2006*3ac0a46fSAndroid Build Coastguard Worker #ifdef PDF_ENABLE_V8
2007*3ac0a46fSAndroid Build Coastguard Worker   if (!options.disable_javascript) {
2008*3ac0a46fSAndroid Build Coastguard Worker     isolate.reset();
2009*3ac0a46fSAndroid Build Coastguard Worker     ShutdownV8ForPDFium();
2010*3ac0a46fSAndroid Build Coastguard Worker #ifdef V8_USE_EXTERNAL_STARTUP_DATA
2011*3ac0a46fSAndroid Build Coastguard Worker     free(const_cast<char*>(snapshot.data));
2012*3ac0a46fSAndroid Build Coastguard Worker #endif  // V8_USE_EXTERNAL_STARTUP_DATA
2013*3ac0a46fSAndroid Build Coastguard Worker   }
2014*3ac0a46fSAndroid Build Coastguard Worker #endif  // PDF_ENABLE_V8
2015*3ac0a46fSAndroid Build Coastguard Worker 
2016*3ac0a46fSAndroid Build Coastguard Worker   return 0;
2017*3ac0a46fSAndroid Build Coastguard Worker }
2018