xref: /aosp_15_r20/external/pdfium/fpdfsdk/fpdf_edit_embeddertest.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2016 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 <limits>
6*3ac0a46fSAndroid Build Coastguard Worker #include <memory>
7*3ac0a46fSAndroid Build Coastguard Worker #include <string>
8*3ac0a46fSAndroid Build Coastguard Worker #include <utility>
9*3ac0a46fSAndroid Build Coastguard Worker #include <vector>
10*3ac0a46fSAndroid Build Coastguard Worker 
11*3ac0a46fSAndroid Build Coastguard Worker #include "build/build_config.h"
12*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/font/cpdf_font.h"
13*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/page/cpdf_page.h"
14*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/page/cpdf_pageobject.h"
15*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_array.h"
16*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_dictionary.h"
17*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_number.h"
18*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_stream.h"
19*3ac0a46fSAndroid Build Coastguard Worker #include "core/fpdfapi/parser/cpdf_stream_acc.h"
20*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/fx_codepage.h"
21*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxcrt/fx_system.h"
22*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxge/cfx_defaultrenderdevice.h"
23*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxge/fx_font.h"
24*3ac0a46fSAndroid Build Coastguard Worker #include "fpdfsdk/cpdfsdk_helpers.h"
25*3ac0a46fSAndroid Build Coastguard Worker #include "public/cpp/fpdf_scopers.h"
26*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_annot.h"
27*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdf_edit.h"
28*3ac0a46fSAndroid Build Coastguard Worker #include "public/fpdfview.h"
29*3ac0a46fSAndroid Build Coastguard Worker #include "testing/embedder_test.h"
30*3ac0a46fSAndroid Build Coastguard Worker #include "testing/embedder_test_constants.h"
31*3ac0a46fSAndroid Build Coastguard Worker #include "testing/fx_string_testhelpers.h"
32*3ac0a46fSAndroid Build Coastguard Worker #include "testing/gmock/include/gmock/gmock-matchers.h"
33*3ac0a46fSAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
34*3ac0a46fSAndroid Build Coastguard Worker #include "testing/utils/file_util.h"
35*3ac0a46fSAndroid Build Coastguard Worker #include "testing/utils/hash.h"
36*3ac0a46fSAndroid Build Coastguard Worker #include "testing/utils/path_service.h"
37*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/check.h"
38*3ac0a46fSAndroid Build Coastguard Worker 
39*3ac0a46fSAndroid Build Coastguard Worker using pdfium::HelloWorldChecksum;
40*3ac0a46fSAndroid Build Coastguard Worker using testing::HasSubstr;
41*3ac0a46fSAndroid Build Coastguard Worker using testing::Not;
42*3ac0a46fSAndroid Build Coastguard Worker using testing::UnorderedElementsAreArray;
43*3ac0a46fSAndroid Build Coastguard Worker 
44*3ac0a46fSAndroid Build Coastguard Worker namespace {
45*3ac0a46fSAndroid Build Coastguard Worker 
46*3ac0a46fSAndroid Build Coastguard Worker const char kAllRemovedChecksum[] = "eee4600ac08b458ac7ac2320e225674c";
47*3ac0a46fSAndroid Build Coastguard Worker 
48*3ac0a46fSAndroid Build Coastguard Worker const wchar_t kBottomText[] = L"I'm at the bottom of the page";
49*3ac0a46fSAndroid Build Coastguard Worker 
BottomTextChecksum()50*3ac0a46fSAndroid Build Coastguard Worker const char* BottomTextChecksum() {
51*3ac0a46fSAndroid Build Coastguard Worker   if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
52*3ac0a46fSAndroid Build Coastguard Worker     return "c62d315856a558d2666b80d474831efe";
53*3ac0a46fSAndroid Build Coastguard Worker   }
54*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
55*3ac0a46fSAndroid Build Coastguard Worker   return "81636489006a31fcb00cf29efcdf7909";
56*3ac0a46fSAndroid Build Coastguard Worker #else
57*3ac0a46fSAndroid Build Coastguard Worker   return "891dcb6e914c8360998055f1f47c9727";
58*3ac0a46fSAndroid Build Coastguard Worker #endif
59*3ac0a46fSAndroid Build Coastguard Worker }
60*3ac0a46fSAndroid Build Coastguard Worker 
FirstRemovedChecksum()61*3ac0a46fSAndroid Build Coastguard Worker const char* FirstRemovedChecksum() {
62*3ac0a46fSAndroid Build Coastguard Worker   if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
63*3ac0a46fSAndroid Build Coastguard Worker     return "3006ab2b12d27246eae4faad509ac575";
64*3ac0a46fSAndroid Build Coastguard Worker   }
65*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
66*3ac0a46fSAndroid Build Coastguard Worker   return "a1dc2812692fcc7ee4f01ca77435df9d";
67*3ac0a46fSAndroid Build Coastguard Worker #else
68*3ac0a46fSAndroid Build Coastguard Worker   return "e1477dc3b5b3b9c560814c4d1135a02b";
69*3ac0a46fSAndroid Build Coastguard Worker #endif
70*3ac0a46fSAndroid Build Coastguard Worker }
71*3ac0a46fSAndroid Build Coastguard Worker 
72*3ac0a46fSAndroid Build Coastguard Worker const wchar_t kLoadedFontText[] = L"I am testing my loaded font, WEE.";
73*3ac0a46fSAndroid Build Coastguard Worker 
LoadedFontTextChecksum()74*3ac0a46fSAndroid Build Coastguard Worker const char* LoadedFontTextChecksum() {
75*3ac0a46fSAndroid Build Coastguard Worker   if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
76*3ac0a46fSAndroid Build Coastguard Worker     return "fc2334c350cbd0d2ae6076689da09741";
77*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
78*3ac0a46fSAndroid Build Coastguard Worker   return "0f3e4a7d71f9e7eb8a1a0d69403b9848";
79*3ac0a46fSAndroid Build Coastguard Worker #else
80*3ac0a46fSAndroid Build Coastguard Worker   return "d58570cc045dfb818b92cbabbd1a364c";
81*3ac0a46fSAndroid Build Coastguard Worker #endif
82*3ac0a46fSAndroid Build Coastguard Worker }
83*3ac0a46fSAndroid Build Coastguard Worker 
84*3ac0a46fSAndroid Build Coastguard Worker const char kRedRectangleChecksum[] = "66d02eaa6181e2c069ce2ea99beda497";
85*3ac0a46fSAndroid Build Coastguard Worker 
86*3ac0a46fSAndroid Build Coastguard Worker // In embedded_images.pdf.
87*3ac0a46fSAndroid Build Coastguard Worker const char kEmbeddedImage33Checksum[] = "cb3637934bb3b95a6e4ae1ea9eb9e56e";
88*3ac0a46fSAndroid Build Coastguard Worker 
89*3ac0a46fSAndroid Build Coastguard Worker }  // namespace
90*3ac0a46fSAndroid Build Coastguard Worker 
91*3ac0a46fSAndroid Build Coastguard Worker class FPDFEditEmbedderTest : public EmbedderTest {
92*3ac0a46fSAndroid Build Coastguard Worker  protected:
CreateNewDocument()93*3ac0a46fSAndroid Build Coastguard Worker   FPDF_DOCUMENT CreateNewDocument() {
94*3ac0a46fSAndroid Build Coastguard Worker     CreateEmptyDocumentWithoutFormFillEnvironment();
95*3ac0a46fSAndroid Build Coastguard Worker     cpdf_doc_ = CPDFDocumentFromFPDFDocument(document());
96*3ac0a46fSAndroid Build Coastguard Worker     return document();
97*3ac0a46fSAndroid Build Coastguard Worker   }
98*3ac0a46fSAndroid Build Coastguard Worker 
CheckFontDescriptor(const CPDF_Dictionary * font_dict,int font_type,bool bold,bool italic,pdfium::span<const uint8_t> span)99*3ac0a46fSAndroid Build Coastguard Worker   void CheckFontDescriptor(const CPDF_Dictionary* font_dict,
100*3ac0a46fSAndroid Build Coastguard Worker                            int font_type,
101*3ac0a46fSAndroid Build Coastguard Worker                            bool bold,
102*3ac0a46fSAndroid Build Coastguard Worker                            bool italic,
103*3ac0a46fSAndroid Build Coastguard Worker                            pdfium::span<const uint8_t> span) {
104*3ac0a46fSAndroid Build Coastguard Worker     RetainPtr<const CPDF_Dictionary> font_desc =
105*3ac0a46fSAndroid Build Coastguard Worker         font_dict->GetDictFor("FontDescriptor");
106*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(font_desc);
107*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ("FontDescriptor", font_desc->GetNameFor("Type"));
108*3ac0a46fSAndroid Build Coastguard Worker     ByteString font_name = font_desc->GetNameFor("FontName");
109*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_FALSE(font_name.IsEmpty());
110*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(font_dict->GetNameFor("BaseFont"), font_name);
111*3ac0a46fSAndroid Build Coastguard Worker 
112*3ac0a46fSAndroid Build Coastguard Worker     // Check that the font descriptor has the required keys according to spec
113*3ac0a46fSAndroid Build Coastguard Worker     // 1.7 Table 5.19
114*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(font_desc->KeyExist("Flags"));
115*3ac0a46fSAndroid Build Coastguard Worker 
116*3ac0a46fSAndroid Build Coastguard Worker     int font_flags = font_desc->GetIntegerFor("Flags");
117*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(bold, FontStyleIsForceBold(font_flags));
118*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(italic, FontStyleIsItalic(font_flags));
119*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FontStyleIsNonSymbolic(font_flags));
120*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(font_desc->KeyExist("FontBBox"));
121*3ac0a46fSAndroid Build Coastguard Worker 
122*3ac0a46fSAndroid Build Coastguard Worker     RetainPtr<const CPDF_Array> fontBBox = font_desc->GetArrayFor("FontBBox");
123*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(fontBBox);
124*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(4u, fontBBox->size());
125*3ac0a46fSAndroid Build Coastguard Worker     // Check that the coordinates are in the preferred order according to spec
126*3ac0a46fSAndroid Build Coastguard Worker     // 1.7 Section 3.8.4
127*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(fontBBox->GetIntegerAt(0) < fontBBox->GetIntegerAt(2));
128*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(fontBBox->GetIntegerAt(1) < fontBBox->GetIntegerAt(3));
129*3ac0a46fSAndroid Build Coastguard Worker 
130*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(font_desc->KeyExist("ItalicAngle"));
131*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(font_desc->KeyExist("Ascent"));
132*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(font_desc->KeyExist("Descent"));
133*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(font_desc->KeyExist("CapHeight"));
134*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(font_desc->KeyExist("StemV"));
135*3ac0a46fSAndroid Build Coastguard Worker     ByteString present("FontFile");
136*3ac0a46fSAndroid Build Coastguard Worker     ByteString absent("FontFile2");
137*3ac0a46fSAndroid Build Coastguard Worker     if (font_type == FPDF_FONT_TRUETYPE)
138*3ac0a46fSAndroid Build Coastguard Worker       std::swap(present, absent);
139*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(font_desc->KeyExist(present));
140*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_FALSE(font_desc->KeyExist(absent));
141*3ac0a46fSAndroid Build Coastguard Worker 
142*3ac0a46fSAndroid Build Coastguard Worker     auto streamAcc =
143*3ac0a46fSAndroid Build Coastguard Worker         pdfium::MakeRetain<CPDF_StreamAcc>(font_desc->GetStreamFor(present));
144*3ac0a46fSAndroid Build Coastguard Worker     streamAcc->LoadAllDataRaw();
145*3ac0a46fSAndroid Build Coastguard Worker 
146*3ac0a46fSAndroid Build Coastguard Worker     // Check that the font stream is the one that was provided
147*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(span.size(), streamAcc->GetSize());
148*3ac0a46fSAndroid Build Coastguard Worker     if (font_type == FPDF_FONT_TRUETYPE) {
149*3ac0a46fSAndroid Build Coastguard Worker       ASSERT_EQ(static_cast<int>(span.size()), streamAcc->GetLength1ForTest());
150*3ac0a46fSAndroid Build Coastguard Worker     }
151*3ac0a46fSAndroid Build Coastguard Worker 
152*3ac0a46fSAndroid Build Coastguard Worker     pdfium::span<const uint8_t> stream_data = streamAcc->GetSpan();
153*3ac0a46fSAndroid Build Coastguard Worker     for (size_t j = 0; j < span.size(); j++)
154*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_EQ(span[j], stream_data[j]) << " at byte " << j;
155*3ac0a46fSAndroid Build Coastguard Worker   }
156*3ac0a46fSAndroid Build Coastguard Worker 
CheckCompositeFontWidths(const CPDF_Array * widths_array,CPDF_Font * typed_font)157*3ac0a46fSAndroid Build Coastguard Worker   void CheckCompositeFontWidths(const CPDF_Array* widths_array,
158*3ac0a46fSAndroid Build Coastguard Worker                                 CPDF_Font* typed_font) {
159*3ac0a46fSAndroid Build Coastguard Worker     // Check that W array is in a format that conforms to PDF spec 1.7 section
160*3ac0a46fSAndroid Build Coastguard Worker     // "Glyph Metrics in CIDFonts" (these checks are not
161*3ac0a46fSAndroid Build Coastguard Worker     // implementation-specific).
162*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_GT(widths_array->size(), 1u);
163*3ac0a46fSAndroid Build Coastguard Worker     int num_cids_checked = 0;
164*3ac0a46fSAndroid Build Coastguard Worker     int cur_cid = 0;
165*3ac0a46fSAndroid Build Coastguard Worker     for (size_t idx = 0; idx < widths_array->size(); idx++) {
166*3ac0a46fSAndroid Build Coastguard Worker       int cid = widths_array->GetFloatAt(idx);
167*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_GE(cid, cur_cid);
168*3ac0a46fSAndroid Build Coastguard Worker       ASSERT_FALSE(++idx == widths_array->size());
169*3ac0a46fSAndroid Build Coastguard Worker       RetainPtr<const CPDF_Object> next = widths_array->GetObjectAt(idx);
170*3ac0a46fSAndroid Build Coastguard Worker       if (next->IsArray()) {
171*3ac0a46fSAndroid Build Coastguard Worker         // We are in the c [w1 w2 ...] case
172*3ac0a46fSAndroid Build Coastguard Worker         const CPDF_Array* arr = next->AsArray();
173*3ac0a46fSAndroid Build Coastguard Worker         int cnt = static_cast<int>(arr->size());
174*3ac0a46fSAndroid Build Coastguard Worker         size_t inner_idx = 0;
175*3ac0a46fSAndroid Build Coastguard Worker         for (cur_cid = cid; cur_cid < cid + cnt; cur_cid++) {
176*3ac0a46fSAndroid Build Coastguard Worker           int width = arr->GetFloatAt(inner_idx++);
177*3ac0a46fSAndroid Build Coastguard Worker           EXPECT_EQ(width, typed_font->GetCharWidthF(cur_cid))
178*3ac0a46fSAndroid Build Coastguard Worker               << " at cid " << cur_cid;
179*3ac0a46fSAndroid Build Coastguard Worker         }
180*3ac0a46fSAndroid Build Coastguard Worker         num_cids_checked += cnt;
181*3ac0a46fSAndroid Build Coastguard Worker         continue;
182*3ac0a46fSAndroid Build Coastguard Worker       }
183*3ac0a46fSAndroid Build Coastguard Worker       // Otherwise, are in the c_first c_last w case.
184*3ac0a46fSAndroid Build Coastguard Worker       ASSERT_TRUE(next->IsNumber());
185*3ac0a46fSAndroid Build Coastguard Worker       int last_cid = next->AsNumber()->GetInteger();
186*3ac0a46fSAndroid Build Coastguard Worker       ASSERT_FALSE(++idx == widths_array->size());
187*3ac0a46fSAndroid Build Coastguard Worker       int width = widths_array->GetFloatAt(idx);
188*3ac0a46fSAndroid Build Coastguard Worker       for (cur_cid = cid; cur_cid <= last_cid; cur_cid++) {
189*3ac0a46fSAndroid Build Coastguard Worker         EXPECT_EQ(width, typed_font->GetCharWidthF(cur_cid))
190*3ac0a46fSAndroid Build Coastguard Worker             << " at cid " << cur_cid;
191*3ac0a46fSAndroid Build Coastguard Worker       }
192*3ac0a46fSAndroid Build Coastguard Worker       num_cids_checked += last_cid - cid + 1;
193*3ac0a46fSAndroid Build Coastguard Worker     }
194*3ac0a46fSAndroid Build Coastguard Worker     // Make sure we have a good amount of cids described
195*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_GT(num_cids_checked, 200);
196*3ac0a46fSAndroid Build Coastguard Worker   }
cpdf_doc()197*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Document* cpdf_doc() { return cpdf_doc_; }
198*3ac0a46fSAndroid Build Coastguard Worker 
199*3ac0a46fSAndroid Build Coastguard Worker  private:
200*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Document* cpdf_doc_;
201*3ac0a46fSAndroid Build Coastguard Worker };
202*3ac0a46fSAndroid Build Coastguard Worker 
203*3ac0a46fSAndroid Build Coastguard Worker namespace {
204*3ac0a46fSAndroid Build Coastguard Worker 
205*3ac0a46fSAndroid Build Coastguard Worker const char kExpectedPDF[] =
206*3ac0a46fSAndroid Build Coastguard Worker     "%PDF-1.7\r\n"
207*3ac0a46fSAndroid Build Coastguard Worker     "%\xA1\xB3\xC5\xD7\r\n"
208*3ac0a46fSAndroid Build Coastguard Worker     "1 0 obj\r\n"
209*3ac0a46fSAndroid Build Coastguard Worker     "<</Pages 2 0 R /Type/Catalog>>\r\n"
210*3ac0a46fSAndroid Build Coastguard Worker     "endobj\r\n"
211*3ac0a46fSAndroid Build Coastguard Worker     "2 0 obj\r\n"
212*3ac0a46fSAndroid Build Coastguard Worker     "<</Count 1/Kids\\[ 4 0 R \\]/Type/Pages>>\r\n"
213*3ac0a46fSAndroid Build Coastguard Worker     "endobj\r\n"
214*3ac0a46fSAndroid Build Coastguard Worker     "3 0 obj\r\n"
215*3ac0a46fSAndroid Build Coastguard Worker     "<</CreationDate\\(D:.*\\)/Creator\\(PDFium\\)>>\r\n"
216*3ac0a46fSAndroid Build Coastguard Worker     "endobj\r\n"
217*3ac0a46fSAndroid Build Coastguard Worker     "4 0 obj\r\n"
218*3ac0a46fSAndroid Build Coastguard Worker     "<</MediaBox\\[ 0 0 640 480\\]/Parent 2 0 R "
219*3ac0a46fSAndroid Build Coastguard Worker     "/Resources<<>>"
220*3ac0a46fSAndroid Build Coastguard Worker     "/Rotate 0/Type/Page"
221*3ac0a46fSAndroid Build Coastguard Worker     ">>\r\n"
222*3ac0a46fSAndroid Build Coastguard Worker     "endobj\r\n"
223*3ac0a46fSAndroid Build Coastguard Worker     "xref\r\n"
224*3ac0a46fSAndroid Build Coastguard Worker     "0 5\r\n"
225*3ac0a46fSAndroid Build Coastguard Worker     "0000000000 65535 f\r\n"
226*3ac0a46fSAndroid Build Coastguard Worker     "0000000017 00000 n\r\n"
227*3ac0a46fSAndroid Build Coastguard Worker     "0000000066 00000 n\r\n"
228*3ac0a46fSAndroid Build Coastguard Worker     "0000000122 00000 n\r\n"
229*3ac0a46fSAndroid Build Coastguard Worker     "0000000192 00000 n\r\n"
230*3ac0a46fSAndroid Build Coastguard Worker     "trailer\r\n"
231*3ac0a46fSAndroid Build Coastguard Worker     "<<\r\n"
232*3ac0a46fSAndroid Build Coastguard Worker     "/Root 1 0 R\r\n"
233*3ac0a46fSAndroid Build Coastguard Worker     "/Info 3 0 R\r\n"
234*3ac0a46fSAndroid Build Coastguard Worker     "/Size 5/ID\\[<.*><.*>\\]>>\r\n"
235*3ac0a46fSAndroid Build Coastguard Worker     "startxref\r\n"
236*3ac0a46fSAndroid Build Coastguard Worker     "285\r\n"
237*3ac0a46fSAndroid Build Coastguard Worker     "%%EOF\r\n";
238*3ac0a46fSAndroid Build Coastguard Worker 
239*3ac0a46fSAndroid Build Coastguard Worker }  // namespace
240*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,EmbedNotoSansSCFont)241*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, EmbedNotoSansSCFont) {
242*3ac0a46fSAndroid Build Coastguard Worker   CreateEmptyDocument();
243*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFPage page(FPDFPage_New(document(), 0, 400, 400));
244*3ac0a46fSAndroid Build Coastguard Worker   std::string font_path;
245*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(PathService::GetThirdPartyFilePath(
246*3ac0a46fSAndroid Build Coastguard Worker       "NotoSansCJK/NotoSansSC-Regular.subset.otf", &font_path));
247*3ac0a46fSAndroid Build Coastguard Worker 
248*3ac0a46fSAndroid Build Coastguard Worker   size_t file_length = 0;
249*3ac0a46fSAndroid Build Coastguard Worker   std::unique_ptr<char, pdfium::FreeDeleter> font_data =
250*3ac0a46fSAndroid Build Coastguard Worker       GetFileContents(font_path.c_str(), &file_length);
251*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(font_data);
252*3ac0a46fSAndroid Build Coastguard Worker 
253*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFFont font(FPDFText_LoadFont(
254*3ac0a46fSAndroid Build Coastguard Worker       document(), reinterpret_cast<const uint8_t*>(font_data.get()),
255*3ac0a46fSAndroid Build Coastguard Worker       file_length, FPDF_FONT_TRUETYPE, /*cid=*/true));
256*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT text_object =
257*3ac0a46fSAndroid Build Coastguard Worker       FPDFPageObj_CreateTextObj(document(), font.get(), 20.0f);
258*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(text_object);
259*3ac0a46fSAndroid Build Coastguard Worker 
260*3ac0a46fSAndroid Build Coastguard Worker   // Test the characters which are either mapped to one single unicode or
261*3ac0a46fSAndroid Build Coastguard Worker   // multiple unicodes in the embedded font.
262*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFWideString text = GetFPDFWideString(L"这是第一句。 这是第二行。");
263*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
264*3ac0a46fSAndroid Build Coastguard Worker 
265*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 50, 200);
266*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page.get(), text_object);
267*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
268*3ac0a46fSAndroid Build Coastguard Worker 
269*3ac0a46fSAndroid Build Coastguard Worker   const char* checksum = []() {
270*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
271*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
272*3ac0a46fSAndroid Build Coastguard Worker       return "9a31fb87d1c6d2346bba22d1196041cd";
273*3ac0a46fSAndroid Build Coastguard Worker #else
274*3ac0a46fSAndroid Build Coastguard Worker       return "5bb65e15fc0a685934cd5006dec08a76";
275*3ac0a46fSAndroid Build Coastguard Worker #endif
276*3ac0a46fSAndroid Build Coastguard Worker     }
277*3ac0a46fSAndroid Build Coastguard Worker     return "9a31fb87d1c6d2346bba22d1196041cd";
278*3ac0a46fSAndroid Build Coastguard Worker   }();
279*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
280*3ac0a46fSAndroid Build Coastguard Worker   CompareBitmap(page_bitmap.get(), 400, 400, checksum);
281*3ac0a46fSAndroid Build Coastguard Worker 
282*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
283*3ac0a46fSAndroid Build Coastguard Worker   VerifySavedDocument(400, 400, checksum);
284*3ac0a46fSAndroid Build Coastguard Worker }
285*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,EmbedNotoSansSCFontWithCharcodes)286*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, EmbedNotoSansSCFontWithCharcodes) {
287*3ac0a46fSAndroid Build Coastguard Worker   CreateEmptyDocument();
288*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFPage page(FPDFPage_New(document(), 0, 400, 400));
289*3ac0a46fSAndroid Build Coastguard Worker   std::string font_path;
290*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(PathService::GetThirdPartyFilePath(
291*3ac0a46fSAndroid Build Coastguard Worker       "NotoSansCJK/NotoSansSC-Regular.subset.otf", &font_path));
292*3ac0a46fSAndroid Build Coastguard Worker 
293*3ac0a46fSAndroid Build Coastguard Worker   size_t file_length = 0;
294*3ac0a46fSAndroid Build Coastguard Worker   std::unique_ptr<char, pdfium::FreeDeleter> font_data =
295*3ac0a46fSAndroid Build Coastguard Worker       GetFileContents(font_path.c_str(), &file_length);
296*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(font_data);
297*3ac0a46fSAndroid Build Coastguard Worker 
298*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFFont font(FPDFText_LoadFont(
299*3ac0a46fSAndroid Build Coastguard Worker       document(), reinterpret_cast<const uint8_t*>(font_data.get()),
300*3ac0a46fSAndroid Build Coastguard Worker       file_length, FPDF_FONT_TRUETYPE, /*cid=*/true));
301*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT text_object =
302*3ac0a46fSAndroid Build Coastguard Worker       FPDFPageObj_CreateTextObj(document(), font.get(), 20.0f);
303*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(text_object);
304*3ac0a46fSAndroid Build Coastguard Worker 
305*3ac0a46fSAndroid Build Coastguard Worker   // Same as `text` in the EmbedNotoSansSCFont test case above.
306*3ac0a46fSAndroid Build Coastguard Worker   const std::vector<uint32_t> charcodes = {9, 6, 7, 3, 5, 2, 1,
307*3ac0a46fSAndroid Build Coastguard Worker                                            9, 6, 7, 4, 8, 2};
308*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(
309*3ac0a46fSAndroid Build Coastguard Worker       FPDFText_SetCharcodes(text_object, charcodes.data(), charcodes.size()));
310*3ac0a46fSAndroid Build Coastguard Worker 
311*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 50, 200);
312*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page.get(), text_object);
313*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
314*3ac0a46fSAndroid Build Coastguard Worker 
315*3ac0a46fSAndroid Build Coastguard Worker   const char* checksum = []() {
316*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
317*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
318*3ac0a46fSAndroid Build Coastguard Worker       return "9a31fb87d1c6d2346bba22d1196041cd";
319*3ac0a46fSAndroid Build Coastguard Worker #else
320*3ac0a46fSAndroid Build Coastguard Worker       return "5bb65e15fc0a685934cd5006dec08a76";
321*3ac0a46fSAndroid Build Coastguard Worker #endif
322*3ac0a46fSAndroid Build Coastguard Worker     }
323*3ac0a46fSAndroid Build Coastguard Worker     return "9a31fb87d1c6d2346bba22d1196041cd";
324*3ac0a46fSAndroid Build Coastguard Worker   }();
325*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
326*3ac0a46fSAndroid Build Coastguard Worker   CompareBitmap(page_bitmap.get(), 400, 400, checksum);
327*3ac0a46fSAndroid Build Coastguard Worker 
328*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
329*3ac0a46fSAndroid Build Coastguard Worker   VerifySavedDocument(400, 400, checksum);
330*3ac0a46fSAndroid Build Coastguard Worker }
331*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,EmptyCreation)332*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, EmptyCreation) {
333*3ac0a46fSAndroid Build Coastguard Worker   CreateEmptyDocument();
334*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = FPDFPage_New(document(), 0, 640.0, 480.0);
335*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(page);
336*3ac0a46fSAndroid Build Coastguard Worker   // The FPDFPage_GenerateContent call should do nothing.
337*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
338*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
339*3ac0a46fSAndroid Build Coastguard Worker 
340*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_THAT(GetString(), testing::MatchesRegex(std::string(
341*3ac0a46fSAndroid Build Coastguard Worker                                kExpectedPDF, sizeof(kExpectedPDF))));
342*3ac0a46fSAndroid Build Coastguard Worker   FPDF_ClosePage(page);
343*3ac0a46fSAndroid Build Coastguard Worker }
344*3ac0a46fSAndroid Build Coastguard Worker 
345*3ac0a46fSAndroid Build Coastguard Worker // Regression test for https://crbug.com/667012
TEST_F(FPDFEditEmbedderTest,RasterizePDF)346*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, RasterizePDF) {
347*3ac0a46fSAndroid Build Coastguard Worker   const char kAllBlackChecksum[] = "5708fc5c4a8bd0abde99c8e8f0390615";
348*3ac0a46fSAndroid Build Coastguard Worker 
349*3ac0a46fSAndroid Build Coastguard Worker   // Get the bitmap for the original document.
350*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFBitmap orig_bitmap;
351*3ac0a46fSAndroid Build Coastguard Worker   {
352*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(OpenDocument("black.pdf"));
353*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGE orig_page = LoadPage(0);
354*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(orig_page);
355*3ac0a46fSAndroid Build Coastguard Worker     orig_bitmap = RenderLoadedPage(orig_page);
356*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(orig_bitmap.get(), 612, 792, kAllBlackChecksum);
357*3ac0a46fSAndroid Build Coastguard Worker     UnloadPage(orig_page);
358*3ac0a46fSAndroid Build Coastguard Worker   }
359*3ac0a46fSAndroid Build Coastguard Worker 
360*3ac0a46fSAndroid Build Coastguard Worker   // Create a new document from |orig_bitmap| and save it.
361*3ac0a46fSAndroid Build Coastguard Worker   {
362*3ac0a46fSAndroid Build Coastguard Worker     FPDF_DOCUMENT temp_doc = FPDF_CreateNewDocument();
363*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGE temp_page = FPDFPage_New(temp_doc, 0, 612, 792);
364*3ac0a46fSAndroid Build Coastguard Worker 
365*3ac0a46fSAndroid Build Coastguard Worker     // Add the bitmap to an image object and add the image object to the output
366*3ac0a46fSAndroid Build Coastguard Worker     // page.
367*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT temp_img = FPDFPageObj_NewImageObj(temp_doc);
368*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(
369*3ac0a46fSAndroid Build Coastguard Worker         FPDFImageObj_SetBitmap(&temp_page, 1, temp_img, orig_bitmap.get()));
370*3ac0a46fSAndroid Build Coastguard Worker     static constexpr FS_MATRIX kLetterScaleMatrix{612, 0, 0, 792, 0, 0};
371*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPageObj_SetMatrix(temp_img, &kLetterScaleMatrix));
372*3ac0a46fSAndroid Build Coastguard Worker     FPDFPage_InsertObject(temp_page, temp_img);
373*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPage_GenerateContent(temp_page));
374*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDF_SaveAsCopy(temp_doc, this, 0));
375*3ac0a46fSAndroid Build Coastguard Worker     FPDF_ClosePage(temp_page);
376*3ac0a46fSAndroid Build Coastguard Worker     FPDF_CloseDocument(temp_doc);
377*3ac0a46fSAndroid Build Coastguard Worker   }
378*3ac0a46fSAndroid Build Coastguard Worker 
379*3ac0a46fSAndroid Build Coastguard Worker   // Get the generated content. Make sure it is at least as big as the original
380*3ac0a46fSAndroid Build Coastguard Worker   // PDF.
381*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_GT(GetString().size(), 923u);
382*3ac0a46fSAndroid Build Coastguard Worker   VerifySavedDocument(612, 792, kAllBlackChecksum);
383*3ac0a46fSAndroid Build Coastguard Worker }
384*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,AddPaths)385*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, AddPaths) {
386*3ac0a46fSAndroid Build Coastguard Worker   // Start with a blank page
387*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
388*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
389*3ac0a46fSAndroid Build Coastguard Worker 
390*3ac0a46fSAndroid Build Coastguard Worker   // We will first add a red rectangle
391*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
392*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(red_rect);
393*3ac0a46fSAndroid Build Coastguard Worker   // Expect false when trying to set colors out of range
394*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPageObj_SetStrokeColor(red_rect, 100, 100, 100, 300));
395*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPageObj_SetFillColor(red_rect, 200, 256, 200, 0));
396*3ac0a46fSAndroid Build Coastguard Worker 
397*3ac0a46fSAndroid Build Coastguard Worker   // Fill rectangle with red and insert to the page
398*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
399*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
400*3ac0a46fSAndroid Build Coastguard Worker 
401*3ac0a46fSAndroid Build Coastguard Worker   int fillmode = FPDF_FILLMODE_NONE;
402*3ac0a46fSAndroid Build Coastguard Worker   FPDF_BOOL stroke = true;
403*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_GetDrawMode(red_rect, &fillmode, &stroke));
404*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_FILLMODE_ALTERNATE, fillmode);
405*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(stroke);
406*3ac0a46fSAndroid Build Coastguard Worker 
407*3ac0a46fSAndroid Build Coastguard Worker   static constexpr FS_MATRIX kMatrix = {1, 2, 3, 4, 5, 6};
408*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetMatrix(red_rect, &kMatrix));
409*3ac0a46fSAndroid Build Coastguard Worker 
410*3ac0a46fSAndroid Build Coastguard Worker   FS_MATRIX matrix;
411*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_GetMatrix(red_rect, &matrix));
412*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(1.0f, matrix.a);
413*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(2.0f, matrix.b);
414*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(3.0f, matrix.c);
415*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(4.0f, matrix.d);
416*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(5.0f, matrix.e);
417*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(6.0f, matrix.f);
418*3ac0a46fSAndroid Build Coastguard Worker 
419*3ac0a46fSAndroid Build Coastguard Worker   // Set back the identity matrix.
420*3ac0a46fSAndroid Build Coastguard Worker   matrix = {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f};
421*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetMatrix(red_rect, &matrix));
422*3ac0a46fSAndroid Build Coastguard Worker 
423*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page, red_rect);
424*3ac0a46fSAndroid Build Coastguard Worker   {
425*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
426*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792, kRedRectangleChecksum);
427*3ac0a46fSAndroid Build Coastguard Worker   }
428*3ac0a46fSAndroid Build Coastguard Worker 
429*3ac0a46fSAndroid Build Coastguard Worker   // Now add to that a green rectangle with some medium alpha
430*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(100, 100, 40, 40);
431*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(green_rect, 0, 255, 0, 128));
432*3ac0a46fSAndroid Build Coastguard Worker 
433*3ac0a46fSAndroid Build Coastguard Worker   // Make sure the type of the rectangle is a path.
434*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_PAGEOBJ_PATH, FPDFPageObj_GetType(green_rect));
435*3ac0a46fSAndroid Build Coastguard Worker 
436*3ac0a46fSAndroid Build Coastguard Worker   // Make sure we get back the same color we set previously.
437*3ac0a46fSAndroid Build Coastguard Worker   unsigned int R;
438*3ac0a46fSAndroid Build Coastguard Worker   unsigned int G;
439*3ac0a46fSAndroid Build Coastguard Worker   unsigned int B;
440*3ac0a46fSAndroid Build Coastguard Worker   unsigned int A;
441*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_GetFillColor(green_rect, &R, &G, &B, &A));
442*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(0u, R);
443*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(255u, G);
444*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(0u, B);
445*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(128u, A);
446*3ac0a46fSAndroid Build Coastguard Worker 
447*3ac0a46fSAndroid Build Coastguard Worker   // Make sure the path has 5 points (1 CFX_Path::Point::Type::kMove and 4
448*3ac0a46fSAndroid Build Coastguard Worker   // CFX_Path::Point::Type::kLine).
449*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(5, FPDFPath_CountSegments(green_rect));
450*3ac0a46fSAndroid Build Coastguard Worker   // Verify actual coordinates.
451*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(green_rect, 0);
452*3ac0a46fSAndroid Build Coastguard Worker   float x;
453*3ac0a46fSAndroid Build Coastguard Worker   float y;
454*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
455*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(100, x);
456*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(100, y);
457*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
458*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
459*3ac0a46fSAndroid Build Coastguard Worker   segment = FPDFPath_GetPathSegment(green_rect, 1);
460*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
461*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(100, x);
462*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(140, y);
463*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
464*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
465*3ac0a46fSAndroid Build Coastguard Worker   segment = FPDFPath_GetPathSegment(green_rect, 2);
466*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
467*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(140, x);
468*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(140, y);
469*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
470*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
471*3ac0a46fSAndroid Build Coastguard Worker   segment = FPDFPath_GetPathSegment(green_rect, 3);
472*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
473*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(140, x);
474*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(100, y);
475*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
476*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
477*3ac0a46fSAndroid Build Coastguard Worker   segment = FPDFPath_GetPathSegment(green_rect, 4);
478*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
479*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(100, x);
480*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(100, y);
481*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
482*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetClose(segment));
483*3ac0a46fSAndroid Build Coastguard Worker 
484*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_WINDING, 0));
485*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page, green_rect);
486*3ac0a46fSAndroid Build Coastguard Worker   {
487*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
488*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792,
489*3ac0a46fSAndroid Build Coastguard Worker                   "7b0b87604594e773add528fae567a558");
490*3ac0a46fSAndroid Build Coastguard Worker   }
491*3ac0a46fSAndroid Build Coastguard Worker 
492*3ac0a46fSAndroid Build Coastguard Worker   // Add a black triangle.
493*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(400, 100);
494*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(black_path, 0, 0, 0, 200));
495*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
496*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_LineTo(black_path, 400, 200));
497*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_LineTo(black_path, 300, 100));
498*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_Close(black_path));
499*3ac0a46fSAndroid Build Coastguard Worker 
500*3ac0a46fSAndroid Build Coastguard Worker   // Make sure the path has 3 points (1 CFX_Path::Point::Type::kMove and 2
501*3ac0a46fSAndroid Build Coastguard Worker   // CFX_Path::Point::Type::kLine).
502*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(3, FPDFPath_CountSegments(black_path));
503*3ac0a46fSAndroid Build Coastguard Worker   // Verify actual coordinates.
504*3ac0a46fSAndroid Build Coastguard Worker   segment = FPDFPath_GetPathSegment(black_path, 0);
505*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
506*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(400, x);
507*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(100, y);
508*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
509*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
510*3ac0a46fSAndroid Build Coastguard Worker   segment = FPDFPath_GetPathSegment(black_path, 1);
511*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
512*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(400, x);
513*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(200, y);
514*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
515*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
516*3ac0a46fSAndroid Build Coastguard Worker   segment = FPDFPath_GetPathSegment(black_path, 2);
517*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
518*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(300, x);
519*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(100, y);
520*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
521*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetClose(segment));
522*3ac0a46fSAndroid Build Coastguard Worker   // Make sure out of bounds index access fails properly.
523*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPath_GetPathSegment(black_path, 3));
524*3ac0a46fSAndroid Build Coastguard Worker 
525*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page, black_path);
526*3ac0a46fSAndroid Build Coastguard Worker   {
527*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
528*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792,
529*3ac0a46fSAndroid Build Coastguard Worker                   "eadc8020a14dfcf091da2688733d8806");
530*3ac0a46fSAndroid Build Coastguard Worker   }
531*3ac0a46fSAndroid Build Coastguard Worker 
532*3ac0a46fSAndroid Build Coastguard Worker   // Now add a more complex blue path.
533*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT blue_path = FPDFPageObj_CreateNewPath(200, 200);
534*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(blue_path, 0, 0, 255, 255));
535*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_SetDrawMode(blue_path, FPDF_FILLMODE_WINDING, 0));
536*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_LineTo(blue_path, 230, 230));
537*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 250, 250, 280, 280, 300, 300));
538*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_LineTo(blue_path, 325, 325));
539*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_LineTo(blue_path, 350, 325));
540*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 375, 330, 390, 360, 400, 400));
541*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_Close(blue_path));
542*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page, blue_path);
543*3ac0a46fSAndroid Build Coastguard Worker   const char* last_checksum = []() {
544*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
545*3ac0a46fSAndroid Build Coastguard Worker       return "ed14c60702b1489c597c7d46ece7f86d";
546*3ac0a46fSAndroid Build Coastguard Worker     return "9823e1a21bd9b72b6a442ba4f12af946";
547*3ac0a46fSAndroid Build Coastguard Worker   }();
548*3ac0a46fSAndroid Build Coastguard Worker   {
549*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
550*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792, last_checksum);
551*3ac0a46fSAndroid Build Coastguard Worker   }
552*3ac0a46fSAndroid Build Coastguard Worker 
553*3ac0a46fSAndroid Build Coastguard Worker   // Now save the result, closing the page and document
554*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
555*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
556*3ac0a46fSAndroid Build Coastguard Worker   FPDF_ClosePage(page);
557*3ac0a46fSAndroid Build Coastguard Worker 
558*3ac0a46fSAndroid Build Coastguard Worker   // Render the saved result
559*3ac0a46fSAndroid Build Coastguard Worker   VerifySavedDocument(612, 792, last_checksum);
560*3ac0a46fSAndroid Build Coastguard Worker }
561*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,ClipPath)562*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, ClipPath) {
563*3ac0a46fSAndroid Build Coastguard Worker   // Load document with a clipped rectangle.
564*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("clip_path.pdf"));
565*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
566*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
567*3ac0a46fSAndroid Build Coastguard Worker 
568*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFPage_CountObjects(page));
569*3ac0a46fSAndroid Build Coastguard Worker 
570*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT triangle = FPDFPage_GetObject(page, 0);
571*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(triangle);
572*3ac0a46fSAndroid Build Coastguard Worker 
573*3ac0a46fSAndroid Build Coastguard Worker   // Test that we got the expected triangle.
574*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(4, FPDFPath_CountSegments(triangle));
575*3ac0a46fSAndroid Build Coastguard Worker 
576*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(triangle, 0);
577*3ac0a46fSAndroid Build Coastguard Worker   float x;
578*3ac0a46fSAndroid Build Coastguard Worker   float y;
579*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
580*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(10, x);
581*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(10, y);
582*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
583*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
584*3ac0a46fSAndroid Build Coastguard Worker 
585*3ac0a46fSAndroid Build Coastguard Worker   segment = FPDFPath_GetPathSegment(triangle, 1);
586*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
587*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(25, x);
588*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(40, y);
589*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
590*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
591*3ac0a46fSAndroid Build Coastguard Worker 
592*3ac0a46fSAndroid Build Coastguard Worker   segment = FPDFPath_GetPathSegment(triangle, 2);
593*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
594*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(40, x);
595*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(10, y);
596*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
597*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
598*3ac0a46fSAndroid Build Coastguard Worker 
599*3ac0a46fSAndroid Build Coastguard Worker   segment = FPDFPath_GetPathSegment(triangle, 3);
600*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
601*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetClose(segment));
602*3ac0a46fSAndroid Build Coastguard Worker 
603*3ac0a46fSAndroid Build Coastguard Worker   // Test FPDFPageObj_GetClipPath().
604*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(nullptr, FPDFPageObj_GetClipPath(nullptr));
605*3ac0a46fSAndroid Build Coastguard Worker 
606*3ac0a46fSAndroid Build Coastguard Worker   FPDF_CLIPPATH clip_path = FPDFPageObj_GetClipPath(triangle);
607*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(clip_path);
608*3ac0a46fSAndroid Build Coastguard Worker 
609*3ac0a46fSAndroid Build Coastguard Worker   // Test FPDFClipPath_CountPaths().
610*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(-1, FPDFClipPath_CountPaths(nullptr));
611*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFClipPath_CountPaths(clip_path));
612*3ac0a46fSAndroid Build Coastguard Worker 
613*3ac0a46fSAndroid Build Coastguard Worker   // Test FPDFClipPath_CountPathSegments().
614*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(-1, FPDFClipPath_CountPathSegments(nullptr, 0));
615*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(-1, FPDFClipPath_CountPathSegments(clip_path, -1));
616*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(-1, FPDFClipPath_CountPathSegments(clip_path, 1));
617*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(4, FPDFClipPath_CountPathSegments(clip_path, 0));
618*3ac0a46fSAndroid Build Coastguard Worker 
619*3ac0a46fSAndroid Build Coastguard Worker   // FPDFClipPath_GetPathSegment() negative testing.
620*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(nullptr, 0, 0));
621*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, -1, 0));
622*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, 1, 0));
623*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, 0, -1));
624*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, 0, 4));
625*3ac0a46fSAndroid Build Coastguard Worker 
626*3ac0a46fSAndroid Build Coastguard Worker   // FPDFClipPath_GetPathSegment() positive testing.
627*3ac0a46fSAndroid Build Coastguard Worker   segment = FPDFClipPath_GetPathSegment(clip_path, 0, 0);
628*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
629*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(10, x);
630*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(15, y);
631*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
632*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
633*3ac0a46fSAndroid Build Coastguard Worker 
634*3ac0a46fSAndroid Build Coastguard Worker   segment = FPDFClipPath_GetPathSegment(clip_path, 0, 1);
635*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
636*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(40, x);
637*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(15, y);
638*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
639*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
640*3ac0a46fSAndroid Build Coastguard Worker 
641*3ac0a46fSAndroid Build Coastguard Worker   segment = FPDFClipPath_GetPathSegment(clip_path, 0, 2);
642*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
643*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(40, x);
644*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(35, y);
645*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
646*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
647*3ac0a46fSAndroid Build Coastguard Worker 
648*3ac0a46fSAndroid Build Coastguard Worker   segment = FPDFClipPath_GetPathSegment(clip_path, 0, 3);
649*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
650*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(10, x);
651*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(35, y);
652*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
653*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
654*3ac0a46fSAndroid Build Coastguard Worker 
655*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
656*3ac0a46fSAndroid Build Coastguard Worker }
657*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,BUG_1399)658*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, BUG_1399) {
659*3ac0a46fSAndroid Build Coastguard Worker   // Load document with a clipped rectangle.
660*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("bug_1399.pdf"));
661*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
662*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
663*3ac0a46fSAndroid Build Coastguard Worker 
664*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(7, FPDFPage_CountObjects(page));
665*3ac0a46fSAndroid Build Coastguard Worker 
666*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 0);
667*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(obj);
668*3ac0a46fSAndroid Build Coastguard Worker 
669*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPath_CountSegments(obj));
670*3ac0a46fSAndroid Build Coastguard Worker 
671*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(obj, 0);
672*3ac0a46fSAndroid Build Coastguard Worker   float x;
673*3ac0a46fSAndroid Build Coastguard Worker   float y;
674*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
675*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(107.718f, x);
676*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(719.922f, y);
677*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
678*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
679*3ac0a46fSAndroid Build Coastguard Worker 
680*3ac0a46fSAndroid Build Coastguard Worker   segment = FPDFPath_GetPathSegment(obj, 1);
681*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
682*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(394.718f, x);
683*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(719.922f, y);
684*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
685*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
686*3ac0a46fSAndroid Build Coastguard Worker 
687*3ac0a46fSAndroid Build Coastguard Worker   FPDF_CLIPPATH clip_path = FPDFPageObj_GetClipPath(obj);
688*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(clip_path);
689*3ac0a46fSAndroid Build Coastguard Worker 
690*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(-1, FPDFClipPath_CountPaths(clip_path));
691*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(-1, FPDFClipPath_CountPathSegments(clip_path, 0));
692*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFClipPath_GetPathSegment(clip_path, 0, 0));
693*3ac0a46fSAndroid Build Coastguard Worker 
694*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
695*3ac0a46fSAndroid Build Coastguard Worker }
696*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,BUG_1549)697*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, BUG_1549) {
698*3ac0a46fSAndroid Build Coastguard Worker   static const char kOriginalChecksum[] = "126366fb95e6caf8ea196780075b22b2";
699*3ac0a46fSAndroid Build Coastguard Worker   static const char kRemovedChecksum[] = "6ec2f27531927882624b37bc7d8e12f4";
700*3ac0a46fSAndroid Build Coastguard Worker 
701*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("bug_1549.pdf"));
702*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
703*3ac0a46fSAndroid Build Coastguard Worker 
704*3ac0a46fSAndroid Build Coastguard Worker   {
705*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
706*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(bitmap.get(), 100, 150, kOriginalChecksum);
707*3ac0a46fSAndroid Build Coastguard Worker 
708*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFPageObject obj(FPDFPage_GetObject(page, 0));
709*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj.get()));
710*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(FPDFPage_RemoveObject(page, obj.get()));
711*3ac0a46fSAndroid Build Coastguard Worker   }
712*3ac0a46fSAndroid Build Coastguard Worker 
713*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFPage_GenerateContent(page));
714*3ac0a46fSAndroid Build Coastguard Worker 
715*3ac0a46fSAndroid Build Coastguard Worker   {
716*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
717*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(bitmap.get(), 100, 150, kRemovedChecksum);
718*3ac0a46fSAndroid Build Coastguard Worker   }
719*3ac0a46fSAndroid Build Coastguard Worker 
720*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
721*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
722*3ac0a46fSAndroid Build Coastguard Worker 
723*3ac0a46fSAndroid Build Coastguard Worker   // TODO(crbug.com/pdfium/1549): Should be `kRemovedChecksum`.
724*3ac0a46fSAndroid Build Coastguard Worker   VerifySavedDocument(100, 150, "4f9889cd5993db20f1ab37d677ac8d26");
725*3ac0a46fSAndroid Build Coastguard Worker }
726*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,SetText)727*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, SetText) {
728*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text.
729*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("hello_world.pdf"));
730*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
731*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
732*3ac0a46fSAndroid Build Coastguard Worker 
733*3ac0a46fSAndroid Build Coastguard Worker   // Get the "Hello, world!" text object and change it.
734*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPage_CountObjects(page));
735*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
736*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page_object);
737*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFWideString text1 = GetFPDFWideString(L"Changed for SetText test");
738*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFText_SetText(page_object, text1.get()));
739*3ac0a46fSAndroid Build Coastguard Worker 
740*3ac0a46fSAndroid Build Coastguard Worker   // Verify the "Hello, world!" text is gone and "Changed for SetText test" is
741*3ac0a46fSAndroid Build Coastguard Worker   // now displayed.
742*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPage_CountObjects(page));
743*3ac0a46fSAndroid Build Coastguard Worker 
744*3ac0a46fSAndroid Build Coastguard Worker   const char* changed_checksum = []() {
745*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
746*3ac0a46fSAndroid Build Coastguard Worker       return "4a8345a139507932729e07d4831cbe2b";
747*3ac0a46fSAndroid Build Coastguard Worker     }
748*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
749*3ac0a46fSAndroid Build Coastguard Worker     return "b720e83476fd6819d47c533f1f43c728";
750*3ac0a46fSAndroid Build Coastguard Worker #else
751*3ac0a46fSAndroid Build Coastguard Worker     return "9a85b9354a69c61772ed24151c140f46";
752*3ac0a46fSAndroid Build Coastguard Worker #endif
753*3ac0a46fSAndroid Build Coastguard Worker   }();
754*3ac0a46fSAndroid Build Coastguard Worker   {
755*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
756*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, changed_checksum);
757*3ac0a46fSAndroid Build Coastguard Worker   }
758*3ac0a46fSAndroid Build Coastguard Worker 
759*3ac0a46fSAndroid Build Coastguard Worker   // Now save the result.
760*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
761*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
762*3ac0a46fSAndroid Build Coastguard Worker 
763*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
764*3ac0a46fSAndroid Build Coastguard Worker 
765*3ac0a46fSAndroid Build Coastguard Worker   // Re-open the file and check the changes were kept in the saved .pdf.
766*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
767*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
768*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
769*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(2, FPDFPage_CountObjects(saved_page));
770*3ac0a46fSAndroid Build Coastguard Worker   {
771*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
772*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, changed_checksum);
773*3ac0a46fSAndroid Build Coastguard Worker   }
774*3ac0a46fSAndroid Build Coastguard Worker 
775*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
776*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
777*3ac0a46fSAndroid Build Coastguard Worker }
778*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,SetCharcodesBadParams)779*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, SetCharcodesBadParams) {
780*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("hello_world.pdf"));
781*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
782*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
783*3ac0a46fSAndroid Build Coastguard Worker 
784*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPage_CountObjects(page));
785*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
786*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page_object);
787*3ac0a46fSAndroid Build Coastguard Worker 
788*3ac0a46fSAndroid Build Coastguard Worker   const uint32_t kDummyValue = 42;
789*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, nullptr, 0));
790*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, nullptr, 1));
791*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, &kDummyValue, 0));
792*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, &kDummyValue, 1));
793*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFText_SetCharcodes(page_object, nullptr, 1));
794*3ac0a46fSAndroid Build Coastguard Worker 
795*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
796*3ac0a46fSAndroid Build Coastguard Worker }
797*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,SetTextKeepClippingPath)798*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, SetTextKeepClippingPath) {
799*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text, with parts clipped.
800*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("bug_1558.pdf"));
801*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
802*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
803*3ac0a46fSAndroid Build Coastguard Worker 
804*3ac0a46fSAndroid Build Coastguard Worker   const char* original_checksum = []() {
805*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
806*3ac0a46fSAndroid Build Coastguard Worker       return "3c04e3acc732faaf39fb0c19efd056ac";
807*3ac0a46fSAndroid Build Coastguard Worker     }
808*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
809*3ac0a46fSAndroid Build Coastguard Worker     return "ae7a25c85e0e2dd0c5cb9dd5cd37f6df";
810*3ac0a46fSAndroid Build Coastguard Worker #else
811*3ac0a46fSAndroid Build Coastguard Worker     return "7af7fe5b281298261eb66ac2d22f5054";
812*3ac0a46fSAndroid Build Coastguard Worker #endif
813*3ac0a46fSAndroid Build Coastguard Worker   }();
814*3ac0a46fSAndroid Build Coastguard Worker   {
815*3ac0a46fSAndroid Build Coastguard Worker     // When opened before any editing and saving, the clipping path is rendered.
816*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap original_bitmap = RenderPage(page);
817*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(original_bitmap.get(), 200, 200, original_checksum);
818*3ac0a46fSAndroid Build Coastguard Worker   }
819*3ac0a46fSAndroid Build Coastguard Worker 
820*3ac0a46fSAndroid Build Coastguard Worker   // "Change" the text in the objects to their current values to force them to
821*3ac0a46fSAndroid Build Coastguard Worker   // regenerate when saving.
822*3ac0a46fSAndroid Build Coastguard Worker   {
823*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFTextPage text_page(FPDFText_LoadPage(page));
824*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(text_page);
825*3ac0a46fSAndroid Build Coastguard Worker     const int obj_count = FPDFPage_CountObjects(page);
826*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(2, obj_count);
827*3ac0a46fSAndroid Build Coastguard Worker     for (int i = 0; i < obj_count; ++i) {
828*3ac0a46fSAndroid Build Coastguard Worker       FPDF_PAGEOBJECT text_obj = FPDFPage_GetObject(page, i);
829*3ac0a46fSAndroid Build Coastguard Worker       ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_obj));
830*3ac0a46fSAndroid Build Coastguard Worker       unsigned long size =
831*3ac0a46fSAndroid Build Coastguard Worker           FPDFTextObj_GetText(text_obj, text_page.get(),
832*3ac0a46fSAndroid Build Coastguard Worker                               /*buffer=*/nullptr, /*length=*/0);
833*3ac0a46fSAndroid Build Coastguard Worker       ASSERT_GT(size, 0u);
834*3ac0a46fSAndroid Build Coastguard Worker       std::vector<FPDF_WCHAR> buffer = GetFPDFWideStringBuffer(size);
835*3ac0a46fSAndroid Build Coastguard Worker       ASSERT_EQ(size, FPDFTextObj_GetText(text_obj, text_page.get(),
836*3ac0a46fSAndroid Build Coastguard Worker                                           buffer.data(), size));
837*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_TRUE(FPDFText_SetText(text_obj, buffer.data()));
838*3ac0a46fSAndroid Build Coastguard Worker     }
839*3ac0a46fSAndroid Build Coastguard Worker   }
840*3ac0a46fSAndroid Build Coastguard Worker 
841*3ac0a46fSAndroid Build Coastguard Worker   {
842*3ac0a46fSAndroid Build Coastguard Worker     // After editing but before saving, the clipping path is retained.
843*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap edited_bitmap = RenderPage(page);
844*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(edited_bitmap.get(), 200, 200, original_checksum);
845*3ac0a46fSAndroid Build Coastguard Worker   }
846*3ac0a46fSAndroid Build Coastguard Worker 
847*3ac0a46fSAndroid Build Coastguard Worker   // Save the file.
848*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
849*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
850*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
851*3ac0a46fSAndroid Build Coastguard Worker 
852*3ac0a46fSAndroid Build Coastguard Worker   // Open the saved copy and render it.
853*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
854*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
855*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
856*3ac0a46fSAndroid Build Coastguard Worker 
857*3ac0a46fSAndroid Build Coastguard Worker   {
858*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap saved_bitmap = RenderSavedPage(saved_page);
859*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(saved_bitmap.get(), 200, 200, original_checksum);
860*3ac0a46fSAndroid Build Coastguard Worker   }
861*3ac0a46fSAndroid Build Coastguard Worker 
862*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
863*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
864*3ac0a46fSAndroid Build Coastguard Worker }
865*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,BUG_1574)866*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, BUG_1574) {
867*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text within a clipping path.
868*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("bug_1574.pdf"));
869*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
870*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
871*3ac0a46fSAndroid Build Coastguard Worker 
872*3ac0a46fSAndroid Build Coastguard Worker   const char* original_checksum = []() {
873*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
874*3ac0a46fSAndroid Build Coastguard Worker       return "d76a31d931a350f0809226a41029a9a4";
875*3ac0a46fSAndroid Build Coastguard Worker     }
876*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
877*3ac0a46fSAndroid Build Coastguard Worker     return "1226bc2b8072622eb28f52321876e814";
878*3ac0a46fSAndroid Build Coastguard Worker #else
879*3ac0a46fSAndroid Build Coastguard Worker     return "c5241eef60b9eac68ed1f2a5fd002703";
880*3ac0a46fSAndroid Build Coastguard Worker #endif
881*3ac0a46fSAndroid Build Coastguard Worker   }();
882*3ac0a46fSAndroid Build Coastguard Worker   {
883*3ac0a46fSAndroid Build Coastguard Worker     // When opened before any editing and saving, the text object is rendered.
884*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap original_bitmap = RenderPage(page);
885*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(original_bitmap.get(), 200, 300, original_checksum);
886*3ac0a46fSAndroid Build Coastguard Worker   }
887*3ac0a46fSAndroid Build Coastguard Worker 
888*3ac0a46fSAndroid Build Coastguard Worker   // "Change" the text in the objects to their current values to force them to
889*3ac0a46fSAndroid Build Coastguard Worker   // regenerate when saving.
890*3ac0a46fSAndroid Build Coastguard Worker   {
891*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFTextPage text_page(FPDFText_LoadPage(page));
892*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(text_page);
893*3ac0a46fSAndroid Build Coastguard Worker 
894*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(2, FPDFPage_CountObjects(page));
895*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT text_obj = FPDFPage_GetObject(page, 1);
896*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_obj));
897*3ac0a46fSAndroid Build Coastguard Worker 
898*3ac0a46fSAndroid Build Coastguard Worker     unsigned long size = FPDFTextObj_GetText(text_obj, text_page.get(),
899*3ac0a46fSAndroid Build Coastguard Worker                                              /*buffer=*/nullptr, /*length=*/0);
900*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_GT(size, 0u);
901*3ac0a46fSAndroid Build Coastguard Worker     std::vector<FPDF_WCHAR> buffer = GetFPDFWideStringBuffer(size);
902*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(size, FPDFTextObj_GetText(text_obj, text_page.get(),
903*3ac0a46fSAndroid Build Coastguard Worker                                         buffer.data(), size));
904*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFText_SetText(text_obj, buffer.data()));
905*3ac0a46fSAndroid Build Coastguard Worker   }
906*3ac0a46fSAndroid Build Coastguard Worker 
907*3ac0a46fSAndroid Build Coastguard Worker   // Save the file.
908*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
909*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
910*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
911*3ac0a46fSAndroid Build Coastguard Worker 
912*3ac0a46fSAndroid Build Coastguard Worker   // Open the saved copy and render it.
913*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
914*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
915*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
916*3ac0a46fSAndroid Build Coastguard Worker 
917*3ac0a46fSAndroid Build Coastguard Worker   {
918*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap saved_bitmap = RenderSavedPage(saved_page);
919*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(saved_bitmap.get(), 200, 300, original_checksum);
920*3ac0a46fSAndroid Build Coastguard Worker   }
921*3ac0a46fSAndroid Build Coastguard Worker 
922*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
923*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
924*3ac0a46fSAndroid Build Coastguard Worker }
925*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,RemoveTextObject)926*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, RemoveTextObject) {
927*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text.
928*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("hello_world.pdf"));
929*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
930*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
931*3ac0a46fSAndroid Build Coastguard Worker 
932*3ac0a46fSAndroid Build Coastguard Worker   // Show what the original file looks like.
933*3ac0a46fSAndroid Build Coastguard Worker   {
934*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
935*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, HelloWorldChecksum());
936*3ac0a46fSAndroid Build Coastguard Worker   }
937*3ac0a46fSAndroid Build Coastguard Worker 
938*3ac0a46fSAndroid Build Coastguard Worker   // Get the "Hello, world!" text object and remove it.
939*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPage_CountObjects(page));
940*3ac0a46fSAndroid Build Coastguard Worker   {
941*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFPageObject page_object(FPDFPage_GetObject(page, 0));
942*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(page_object);
943*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(page_object.get()));
944*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object.get()));
945*3ac0a46fSAndroid Build Coastguard Worker   }
946*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFPage_CountObjects(page));
947*3ac0a46fSAndroid Build Coastguard Worker 
948*3ac0a46fSAndroid Build Coastguard Worker   // Verify the "Hello, world!" text is gone.
949*3ac0a46fSAndroid Build Coastguard Worker   {
950*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
951*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, FirstRemovedChecksum());
952*3ac0a46fSAndroid Build Coastguard Worker   }
953*3ac0a46fSAndroid Build Coastguard Worker 
954*3ac0a46fSAndroid Build Coastguard Worker   // Verify the rendering again after calling FPDFPage_GenerateContent().
955*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFPage_GenerateContent(page));
956*3ac0a46fSAndroid Build Coastguard Worker   {
957*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
958*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, FirstRemovedChecksum());
959*3ac0a46fSAndroid Build Coastguard Worker   }
960*3ac0a46fSAndroid Build Coastguard Worker 
961*3ac0a46fSAndroid Build Coastguard Worker   // Save the document and verify it after reloading.
962*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
963*3ac0a46fSAndroid Build Coastguard Worker   VerifySavedDocument(200, 200, FirstRemovedChecksum());
964*3ac0a46fSAndroid Build Coastguard Worker 
965*3ac0a46fSAndroid Build Coastguard Worker   // Verify removed/renamed resources are no longer there.
966*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_THAT(GetString(), Not(HasSubstr("/F1")));
967*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_THAT(GetString(), Not(HasSubstr("/F2")));
968*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_THAT(GetString(), Not(HasSubstr("/Times-Roman")));
969*3ac0a46fSAndroid Build Coastguard Worker 
970*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
971*3ac0a46fSAndroid Build Coastguard Worker }
972*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,RemoveTextObjectWithTwoPagesSharingContentStreamAndResources)973*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest,
974*3ac0a46fSAndroid Build Coastguard Worker        RemoveTextObjectWithTwoPagesSharingContentStreamAndResources) {
975*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text.
976*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("hello_world_2_pages.pdf"));
977*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page1 = LoadPage(0);
978*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page1);
979*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page2 = LoadPage(1);
980*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page2);
981*3ac0a46fSAndroid Build Coastguard Worker 
982*3ac0a46fSAndroid Build Coastguard Worker   // Show what the original file looks like.
983*3ac0a46fSAndroid Build Coastguard Worker   {
984*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
985*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page1_bitmap.get(), 200, 200, HelloWorldChecksum());
986*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
987*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
988*3ac0a46fSAndroid Build Coastguard Worker   }
989*3ac0a46fSAndroid Build Coastguard Worker 
990*3ac0a46fSAndroid Build Coastguard Worker   // Get the "Hello, world!" text object from page 1 and remove it.
991*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPage_CountObjects(page1));
992*3ac0a46fSAndroid Build Coastguard Worker   {
993*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFPageObject page_object(FPDFPage_GetObject(page1, 0));
994*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(page_object);
995*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(page_object.get()));
996*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPage_RemoveObject(page1, page_object.get()));
997*3ac0a46fSAndroid Build Coastguard Worker   }
998*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFPage_CountObjects(page1));
999*3ac0a46fSAndroid Build Coastguard Worker 
1000*3ac0a46fSAndroid Build Coastguard Worker   // Verify the "Hello, world!" text is gone from page 1.
1001*3ac0a46fSAndroid Build Coastguard Worker   {
1002*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
1003*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page1_bitmap.get(), 200, 200, FirstRemovedChecksum());
1004*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
1005*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
1006*3ac0a46fSAndroid Build Coastguard Worker   }
1007*3ac0a46fSAndroid Build Coastguard Worker 
1008*3ac0a46fSAndroid Build Coastguard Worker   // Verify the rendering again after calling FPDFPage_GenerateContent().
1009*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFPage_GenerateContent(page1));
1010*3ac0a46fSAndroid Build Coastguard Worker   {
1011*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
1012*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page1_bitmap.get(), 200, 200, FirstRemovedChecksum());
1013*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
1014*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
1015*3ac0a46fSAndroid Build Coastguard Worker   }
1016*3ac0a46fSAndroid Build Coastguard Worker 
1017*3ac0a46fSAndroid Build Coastguard Worker   // Save the document and verify it after reloading.
1018*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1019*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
1020*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page1 = LoadSavedPage(0);
1021*3ac0a46fSAndroid Build Coastguard Worker   VerifySavedRendering(saved_page1, 200, 200, FirstRemovedChecksum());
1022*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page1);
1023*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page2 = LoadSavedPage(1);
1024*3ac0a46fSAndroid Build Coastguard Worker   VerifySavedRendering(saved_page2, 200, 200, HelloWorldChecksum());
1025*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page2);
1026*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
1027*3ac0a46fSAndroid Build Coastguard Worker 
1028*3ac0a46fSAndroid Build Coastguard Worker   std::vector<std::string> split_saved_data = StringSplit(GetString(), '\n');
1029*3ac0a46fSAndroid Build Coastguard Worker   // Verify removed/renamed resources are in the save PDF the correct number of
1030*3ac0a46fSAndroid Build Coastguard Worker   // times.
1031*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_THAT(split_saved_data, Contains(HasSubstr("/F1")).Times(1));
1032*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_THAT(split_saved_data, Contains(HasSubstr("/F2")).Times(1));
1033*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_THAT(split_saved_data, Contains(HasSubstr("/Times-Roman")).Times(1));
1034*3ac0a46fSAndroid Build Coastguard Worker 
1035*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page1);
1036*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page2);
1037*3ac0a46fSAndroid Build Coastguard Worker }
1038*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,RemoveTextObjectWithTwoPagesSharingContentArrayAndResources)1039*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest,
1040*3ac0a46fSAndroid Build Coastguard Worker        RemoveTextObjectWithTwoPagesSharingContentArrayAndResources) {
1041*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text.
1042*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("hello_world_2_pages_split_streams.pdf"));
1043*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page1 = LoadPage(0);
1044*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page1);
1045*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page2 = LoadPage(1);
1046*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page2);
1047*3ac0a46fSAndroid Build Coastguard Worker 
1048*3ac0a46fSAndroid Build Coastguard Worker   // Show what the original file looks like.
1049*3ac0a46fSAndroid Build Coastguard Worker   {
1050*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
1051*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page1_bitmap.get(), 200, 200, HelloWorldChecksum());
1052*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
1053*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
1054*3ac0a46fSAndroid Build Coastguard Worker   }
1055*3ac0a46fSAndroid Build Coastguard Worker 
1056*3ac0a46fSAndroid Build Coastguard Worker   // Get the "Hello, world!" text object from page 1 and remove it.
1057*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPage_CountObjects(page1));
1058*3ac0a46fSAndroid Build Coastguard Worker   {
1059*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFPageObject page_object(FPDFPage_GetObject(page1, 0));
1060*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(page_object);
1061*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(page_object.get()));
1062*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPage_RemoveObject(page1, page_object.get()));
1063*3ac0a46fSAndroid Build Coastguard Worker   }
1064*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFPage_CountObjects(page1));
1065*3ac0a46fSAndroid Build Coastguard Worker 
1066*3ac0a46fSAndroid Build Coastguard Worker   // Verify the "Hello, world!" text is gone from page 1.
1067*3ac0a46fSAndroid Build Coastguard Worker   {
1068*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
1069*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page1_bitmap.get(), 200, 200, FirstRemovedChecksum());
1070*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
1071*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
1072*3ac0a46fSAndroid Build Coastguard Worker   }
1073*3ac0a46fSAndroid Build Coastguard Worker 
1074*3ac0a46fSAndroid Build Coastguard Worker   // Verify the rendering again after calling FPDFPage_GenerateContent().
1075*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFPage_GenerateContent(page1));
1076*3ac0a46fSAndroid Build Coastguard Worker   {
1077*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
1078*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page1_bitmap.get(), 200, 200, FirstRemovedChecksum());
1079*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
1080*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
1081*3ac0a46fSAndroid Build Coastguard Worker   }
1082*3ac0a46fSAndroid Build Coastguard Worker 
1083*3ac0a46fSAndroid Build Coastguard Worker   // Save the document and verify it after reloading.
1084*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1085*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
1086*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page1 = LoadSavedPage(0);
1087*3ac0a46fSAndroid Build Coastguard Worker   VerifySavedRendering(saved_page1, 200, 200, FirstRemovedChecksum());
1088*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page1);
1089*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page2 = LoadSavedPage(1);
1090*3ac0a46fSAndroid Build Coastguard Worker   VerifySavedRendering(saved_page2, 200, 200, HelloWorldChecksum());
1091*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page2);
1092*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
1093*3ac0a46fSAndroid Build Coastguard Worker 
1094*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page1);
1095*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page2);
1096*3ac0a46fSAndroid Build Coastguard Worker }
1097*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,RemoveTextObjectWithTwoPagesSharingResourcesDict)1098*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, RemoveTextObjectWithTwoPagesSharingResourcesDict) {
1099*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text.
1100*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("hello_world_2_pages_shared_resources_dict.pdf"));
1101*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page1 = LoadPage(0);
1102*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page1);
1103*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page2 = LoadPage(1);
1104*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page2);
1105*3ac0a46fSAndroid Build Coastguard Worker 
1106*3ac0a46fSAndroid Build Coastguard Worker   // Show what the original file looks like.
1107*3ac0a46fSAndroid Build Coastguard Worker   {
1108*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
1109*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page1_bitmap.get(), 200, 200, HelloWorldChecksum());
1110*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
1111*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
1112*3ac0a46fSAndroid Build Coastguard Worker   }
1113*3ac0a46fSAndroid Build Coastguard Worker 
1114*3ac0a46fSAndroid Build Coastguard Worker   // Get the "Hello, world!" text object from page 1 and remove it.
1115*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPage_CountObjects(page1));
1116*3ac0a46fSAndroid Build Coastguard Worker   {
1117*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFPageObject page_object(FPDFPage_GetObject(page1, 0));
1118*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(page_object);
1119*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(page_object.get()));
1120*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPage_RemoveObject(page1, page_object.get()));
1121*3ac0a46fSAndroid Build Coastguard Worker   }
1122*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFPage_CountObjects(page1));
1123*3ac0a46fSAndroid Build Coastguard Worker 
1124*3ac0a46fSAndroid Build Coastguard Worker   // Verify the "Hello, world!" text is gone from page 1
1125*3ac0a46fSAndroid Build Coastguard Worker   {
1126*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
1127*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page1_bitmap.get(), 200, 200, FirstRemovedChecksum());
1128*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
1129*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
1130*3ac0a46fSAndroid Build Coastguard Worker   }
1131*3ac0a46fSAndroid Build Coastguard Worker 
1132*3ac0a46fSAndroid Build Coastguard Worker   // Verify the rendering again after calling FPDFPage_GenerateContent().
1133*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFPage_GenerateContent(page1));
1134*3ac0a46fSAndroid Build Coastguard Worker   {
1135*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page1_bitmap = RenderPage(page1);
1136*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page1_bitmap.get(), 200, 200, FirstRemovedChecksum());
1137*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page2_bitmap = RenderPage(page2);
1138*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page2_bitmap.get(), 200, 200, HelloWorldChecksum());
1139*3ac0a46fSAndroid Build Coastguard Worker   }
1140*3ac0a46fSAndroid Build Coastguard Worker 
1141*3ac0a46fSAndroid Build Coastguard Worker   // Save the document and verify it after reloading.
1142*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1143*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
1144*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page1 = LoadSavedPage(0);
1145*3ac0a46fSAndroid Build Coastguard Worker   VerifySavedRendering(saved_page1, 200, 200, FirstRemovedChecksum());
1146*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page1);
1147*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page2 = LoadSavedPage(1);
1148*3ac0a46fSAndroid Build Coastguard Worker   VerifySavedRendering(saved_page2, 200, 200, HelloWorldChecksum());
1149*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page2);
1150*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
1151*3ac0a46fSAndroid Build Coastguard Worker 
1152*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page1);
1153*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page2);
1154*3ac0a46fSAndroid Build Coastguard Worker }
1155*3ac0a46fSAndroid Build Coastguard Worker 
CheckMarkCounts(FPDF_PAGE page,int start_from,int expected_object_count,size_t expected_prime_count,size_t expected_square_count,size_t expected_greater_than_ten_count,size_t expected_bounds_count)1156*3ac0a46fSAndroid Build Coastguard Worker void CheckMarkCounts(FPDF_PAGE page,
1157*3ac0a46fSAndroid Build Coastguard Worker                      int start_from,
1158*3ac0a46fSAndroid Build Coastguard Worker                      int expected_object_count,
1159*3ac0a46fSAndroid Build Coastguard Worker                      size_t expected_prime_count,
1160*3ac0a46fSAndroid Build Coastguard Worker                      size_t expected_square_count,
1161*3ac0a46fSAndroid Build Coastguard Worker                      size_t expected_greater_than_ten_count,
1162*3ac0a46fSAndroid Build Coastguard Worker                      size_t expected_bounds_count) {
1163*3ac0a46fSAndroid Build Coastguard Worker   int object_count = FPDFPage_CountObjects(page);
1164*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(expected_object_count, object_count);
1165*3ac0a46fSAndroid Build Coastguard Worker 
1166*3ac0a46fSAndroid Build Coastguard Worker   size_t prime_count = 0;
1167*3ac0a46fSAndroid Build Coastguard Worker   size_t square_count = 0;
1168*3ac0a46fSAndroid Build Coastguard Worker   size_t greater_than_ten_count = 0;
1169*3ac0a46fSAndroid Build Coastguard Worker   size_t bounds_count = 0;
1170*3ac0a46fSAndroid Build Coastguard Worker   for (int i = 0; i < object_count; ++i) {
1171*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1172*3ac0a46fSAndroid Build Coastguard Worker 
1173*3ac0a46fSAndroid Build Coastguard Worker     int mark_count = FPDFPageObj_CountMarks(page_object);
1174*3ac0a46fSAndroid Build Coastguard Worker     for (int j = 0; j < mark_count; ++j) {
1175*3ac0a46fSAndroid Build Coastguard Worker       FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1176*3ac0a46fSAndroid Build Coastguard Worker 
1177*3ac0a46fSAndroid Build Coastguard Worker       char buffer[256];
1178*3ac0a46fSAndroid Build Coastguard Worker       unsigned long name_len = 999u;
1179*3ac0a46fSAndroid Build Coastguard Worker       ASSERT_TRUE(
1180*3ac0a46fSAndroid Build Coastguard Worker           FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1181*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_GT(name_len, 0u);
1182*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_NE(999u, name_len);
1183*3ac0a46fSAndroid Build Coastguard Worker       std::wstring name =
1184*3ac0a46fSAndroid Build Coastguard Worker           GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1185*3ac0a46fSAndroid Build Coastguard Worker       if (name == L"Prime") {
1186*3ac0a46fSAndroid Build Coastguard Worker         prime_count++;
1187*3ac0a46fSAndroid Build Coastguard Worker       } else if (name == L"Square") {
1188*3ac0a46fSAndroid Build Coastguard Worker         square_count++;
1189*3ac0a46fSAndroid Build Coastguard Worker         int expected_square = start_from + i;
1190*3ac0a46fSAndroid Build Coastguard Worker         EXPECT_EQ(1, FPDFPageObjMark_CountParams(mark));
1191*3ac0a46fSAndroid Build Coastguard Worker 
1192*3ac0a46fSAndroid Build Coastguard Worker         unsigned long get_param_key_return = 999u;
1193*3ac0a46fSAndroid Build Coastguard Worker         ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer),
1194*3ac0a46fSAndroid Build Coastguard Worker                                                 &get_param_key_return));
1195*3ac0a46fSAndroid Build Coastguard Worker         EXPECT_EQ((6u + 1u) * 2u, get_param_key_return);
1196*3ac0a46fSAndroid Build Coastguard Worker         std::wstring key =
1197*3ac0a46fSAndroid Build Coastguard Worker             GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1198*3ac0a46fSAndroid Build Coastguard Worker         EXPECT_EQ(L"Factor", key);
1199*3ac0a46fSAndroid Build Coastguard Worker 
1200*3ac0a46fSAndroid Build Coastguard Worker         EXPECT_EQ(FPDF_OBJECT_NUMBER,
1201*3ac0a46fSAndroid Build Coastguard Worker                   FPDFPageObjMark_GetParamValueType(mark, "Factor"));
1202*3ac0a46fSAndroid Build Coastguard Worker         int square_root;
1203*3ac0a46fSAndroid Build Coastguard Worker         EXPECT_TRUE(
1204*3ac0a46fSAndroid Build Coastguard Worker             FPDFPageObjMark_GetParamIntValue(mark, "Factor", &square_root));
1205*3ac0a46fSAndroid Build Coastguard Worker         EXPECT_EQ(expected_square, square_root * square_root);
1206*3ac0a46fSAndroid Build Coastguard Worker       } else if (name == L"GreaterThanTen") {
1207*3ac0a46fSAndroid Build Coastguard Worker         greater_than_ten_count++;
1208*3ac0a46fSAndroid Build Coastguard Worker       } else if (name == L"Bounds") {
1209*3ac0a46fSAndroid Build Coastguard Worker         bounds_count++;
1210*3ac0a46fSAndroid Build Coastguard Worker         EXPECT_EQ(1, FPDFPageObjMark_CountParams(mark));
1211*3ac0a46fSAndroid Build Coastguard Worker 
1212*3ac0a46fSAndroid Build Coastguard Worker         unsigned long get_param_key_return = 999u;
1213*3ac0a46fSAndroid Build Coastguard Worker         ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer),
1214*3ac0a46fSAndroid Build Coastguard Worker                                                 &get_param_key_return));
1215*3ac0a46fSAndroid Build Coastguard Worker         EXPECT_EQ((8u + 1u) * 2u, get_param_key_return);
1216*3ac0a46fSAndroid Build Coastguard Worker         std::wstring key =
1217*3ac0a46fSAndroid Build Coastguard Worker             GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1218*3ac0a46fSAndroid Build Coastguard Worker         EXPECT_EQ(L"Position", key);
1219*3ac0a46fSAndroid Build Coastguard Worker 
1220*3ac0a46fSAndroid Build Coastguard Worker         EXPECT_EQ(FPDF_OBJECT_STRING,
1221*3ac0a46fSAndroid Build Coastguard Worker                   FPDFPageObjMark_GetParamValueType(mark, "Position"));
1222*3ac0a46fSAndroid Build Coastguard Worker         unsigned long length;
1223*3ac0a46fSAndroid Build Coastguard Worker         EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
1224*3ac0a46fSAndroid Build Coastguard Worker             mark, "Position", buffer, sizeof(buffer), &length));
1225*3ac0a46fSAndroid Build Coastguard Worker         ASSERT_GT(length, 0u);
1226*3ac0a46fSAndroid Build Coastguard Worker         std::wstring value =
1227*3ac0a46fSAndroid Build Coastguard Worker             GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1228*3ac0a46fSAndroid Build Coastguard Worker 
1229*3ac0a46fSAndroid Build Coastguard Worker         // "Position" can be "First", "Last", or "End".
1230*3ac0a46fSAndroid Build Coastguard Worker         if (i == 0) {
1231*3ac0a46fSAndroid Build Coastguard Worker           EXPECT_EQ((5u + 1u) * 2u, length);
1232*3ac0a46fSAndroid Build Coastguard Worker           EXPECT_EQ(L"First", value);
1233*3ac0a46fSAndroid Build Coastguard Worker         } else if (i == object_count - 1) {
1234*3ac0a46fSAndroid Build Coastguard Worker           if (length == (4u + 1u) * 2u) {
1235*3ac0a46fSAndroid Build Coastguard Worker             EXPECT_EQ(L"Last", value);
1236*3ac0a46fSAndroid Build Coastguard Worker           } else if (length == (3u + 1u) * 2u) {
1237*3ac0a46fSAndroid Build Coastguard Worker             EXPECT_EQ(L"End", value);
1238*3ac0a46fSAndroid Build Coastguard Worker           } else {
1239*3ac0a46fSAndroid Build Coastguard Worker             FAIL();
1240*3ac0a46fSAndroid Build Coastguard Worker           }
1241*3ac0a46fSAndroid Build Coastguard Worker         } else {
1242*3ac0a46fSAndroid Build Coastguard Worker           FAIL();
1243*3ac0a46fSAndroid Build Coastguard Worker         }
1244*3ac0a46fSAndroid Build Coastguard Worker       } else {
1245*3ac0a46fSAndroid Build Coastguard Worker         FAIL();
1246*3ac0a46fSAndroid Build Coastguard Worker       }
1247*3ac0a46fSAndroid Build Coastguard Worker     }
1248*3ac0a46fSAndroid Build Coastguard Worker   }
1249*3ac0a46fSAndroid Build Coastguard Worker 
1250*3ac0a46fSAndroid Build Coastguard Worker   // Expect certain number of tagged objects. The test file contains strings
1251*3ac0a46fSAndroid Build Coastguard Worker   // from 1 to 19.
1252*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(expected_prime_count, prime_count);
1253*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(expected_square_count, square_count);
1254*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(expected_greater_than_ten_count, greater_than_ten_count);
1255*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(expected_bounds_count, bounds_count);
1256*3ac0a46fSAndroid Build Coastguard Worker }
1257*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,ReadMarkedObjectsIndirectDict)1258*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, ReadMarkedObjectsIndirectDict) {
1259*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text marked with an indirect property.
1260*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("text_in_page_marked_indirect.pdf"));
1261*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
1262*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
1263*3ac0a46fSAndroid Build Coastguard Worker 
1264*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
1265*3ac0a46fSAndroid Build Coastguard Worker 
1266*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
1267*3ac0a46fSAndroid Build Coastguard Worker }
1268*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,RemoveMarkedObjectsPrime)1269*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, RemoveMarkedObjectsPrime) {
1270*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text.
1271*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
1272*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
1273*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
1274*3ac0a46fSAndroid Build Coastguard Worker 
1275*3ac0a46fSAndroid Build Coastguard Worker   // Show what the original file looks like.
1276*3ac0a46fSAndroid Build Coastguard Worker   {
1277*3ac0a46fSAndroid Build Coastguard Worker     const char* original_checksum = []() {
1278*3ac0a46fSAndroid Build Coastguard Worker       if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
1279*3ac0a46fSAndroid Build Coastguard Worker         return "efc2206b313fff03be8e701907322b06";
1280*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
1281*3ac0a46fSAndroid Build Coastguard Worker #ifdef ARCH_CPU_ARM64
1282*3ac0a46fSAndroid Build Coastguard Worker       return "cdc8e22cf1e7e06999dc456288672a3b";
1283*3ac0a46fSAndroid Build Coastguard Worker #else
1284*3ac0a46fSAndroid Build Coastguard Worker       return "966579fb98206858ce2f0a1f94a74d05";
1285*3ac0a46fSAndroid Build Coastguard Worker #endif  // ARCH_CPU_ARM64
1286*3ac0a46fSAndroid Build Coastguard Worker #else
1287*3ac0a46fSAndroid Build Coastguard Worker       return "3d5a3de53d5866044c2b6bf339742c97";
1288*3ac0a46fSAndroid Build Coastguard Worker #endif  // BUILDFLAG(IS_APPLE)
1289*3ac0a46fSAndroid Build Coastguard Worker     }();
1290*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
1291*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, original_checksum);
1292*3ac0a46fSAndroid Build Coastguard Worker   }
1293*3ac0a46fSAndroid Build Coastguard Worker 
1294*3ac0a46fSAndroid Build Coastguard Worker   constexpr int expected_object_count = 19;
1295*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(page, 1, expected_object_count, 8, 4, 9, 1);
1296*3ac0a46fSAndroid Build Coastguard Worker 
1297*3ac0a46fSAndroid Build Coastguard Worker   // Get all objects marked with "Prime"
1298*3ac0a46fSAndroid Build Coastguard Worker   std::vector<FPDF_PAGEOBJECT> primes;
1299*3ac0a46fSAndroid Build Coastguard Worker   for (int i = 0; i < expected_object_count; ++i) {
1300*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1301*3ac0a46fSAndroid Build Coastguard Worker 
1302*3ac0a46fSAndroid Build Coastguard Worker     int mark_count = FPDFPageObj_CountMarks(page_object);
1303*3ac0a46fSAndroid Build Coastguard Worker     for (int j = 0; j < mark_count; ++j) {
1304*3ac0a46fSAndroid Build Coastguard Worker       FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1305*3ac0a46fSAndroid Build Coastguard Worker 
1306*3ac0a46fSAndroid Build Coastguard Worker       char buffer[256];
1307*3ac0a46fSAndroid Build Coastguard Worker       unsigned long name_len = 999u;
1308*3ac0a46fSAndroid Build Coastguard Worker       ASSERT_TRUE(
1309*3ac0a46fSAndroid Build Coastguard Worker           FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1310*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_GT(name_len, 0u);
1311*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_NE(999u, name_len);
1312*3ac0a46fSAndroid Build Coastguard Worker       std::wstring name =
1313*3ac0a46fSAndroid Build Coastguard Worker           GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1314*3ac0a46fSAndroid Build Coastguard Worker       if (name == L"Prime") {
1315*3ac0a46fSAndroid Build Coastguard Worker         primes.push_back(page_object);
1316*3ac0a46fSAndroid Build Coastguard Worker       }
1317*3ac0a46fSAndroid Build Coastguard Worker     }
1318*3ac0a46fSAndroid Build Coastguard Worker   }
1319*3ac0a46fSAndroid Build Coastguard Worker 
1320*3ac0a46fSAndroid Build Coastguard Worker   // Remove all objects marked with "Prime".
1321*3ac0a46fSAndroid Build Coastguard Worker   for (FPDF_PAGEOBJECT page_object : primes) {
1322*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1323*3ac0a46fSAndroid Build Coastguard Worker     FPDFPageObj_Destroy(page_object);
1324*3ac0a46fSAndroid Build Coastguard Worker   }
1325*3ac0a46fSAndroid Build Coastguard Worker 
1326*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(11, FPDFPage_CountObjects(page));
1327*3ac0a46fSAndroid Build Coastguard Worker   const char* non_primes_checksum = []() {
1328*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
1329*3ac0a46fSAndroid Build Coastguard Worker       return "10a6558c9e40ea837922e6f2882a2d57";
1330*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
1331*3ac0a46fSAndroid Build Coastguard Worker #ifdef ARCH_CPU_ARM64
1332*3ac0a46fSAndroid Build Coastguard Worker     return "23c4aec321547f51591fe7363a9ea2d6";
1333*3ac0a46fSAndroid Build Coastguard Worker #else
1334*3ac0a46fSAndroid Build Coastguard Worker     return "6e19a4dd674b522cd39cf41956559bd6";
1335*3ac0a46fSAndroid Build Coastguard Worker #endif  // ARCH_CPU_ARM64
1336*3ac0a46fSAndroid Build Coastguard Worker #else
1337*3ac0a46fSAndroid Build Coastguard Worker     return "bc8623c052f12376c3d8dd09a6cd27df";
1338*3ac0a46fSAndroid Build Coastguard Worker #endif  // BUILDFLAG(IS_APPLE)
1339*3ac0a46fSAndroid Build Coastguard Worker   }();
1340*3ac0a46fSAndroid Build Coastguard Worker   const char* non_primes_after_save_checksum = []() {
1341*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
1342*3ac0a46fSAndroid Build Coastguard Worker       return "10a6558c9e40ea837922e6f2882a2d57";
1343*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
1344*3ac0a46fSAndroid Build Coastguard Worker #ifdef ARCH_CPU_ARM64
1345*3ac0a46fSAndroid Build Coastguard Worker     return "6bb1ea0d0a512f29edabda33064a0725";
1346*3ac0a46fSAndroid Build Coastguard Worker #else
1347*3ac0a46fSAndroid Build Coastguard Worker     return "3cb35c681f8fb5a43a49146ac7caa818";
1348*3ac0a46fSAndroid Build Coastguard Worker #endif  // ARCH_CPU_ARM64
1349*3ac0a46fSAndroid Build Coastguard Worker #else
1350*3ac0a46fSAndroid Build Coastguard Worker     return "bc8623c052f12376c3d8dd09a6cd27df";
1351*3ac0a46fSAndroid Build Coastguard Worker #endif  // BUILDFLAG(IS_APPLE)
1352*3ac0a46fSAndroid Build Coastguard Worker   }();
1353*3ac0a46fSAndroid Build Coastguard Worker   {
1354*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
1355*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, non_primes_checksum);
1356*3ac0a46fSAndroid Build Coastguard Worker   }
1357*3ac0a46fSAndroid Build Coastguard Worker 
1358*3ac0a46fSAndroid Build Coastguard Worker   // Save the file.
1359*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
1360*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1361*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
1362*3ac0a46fSAndroid Build Coastguard Worker 
1363*3ac0a46fSAndroid Build Coastguard Worker   // Re-open the file and check the prime marks are not there anymore.
1364*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
1365*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
1366*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
1367*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(11, FPDFPage_CountObjects(saved_page));
1368*3ac0a46fSAndroid Build Coastguard Worker 
1369*3ac0a46fSAndroid Build Coastguard Worker   {
1370*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
1371*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, non_primes_after_save_checksum);
1372*3ac0a46fSAndroid Build Coastguard Worker   }
1373*3ac0a46fSAndroid Build Coastguard Worker 
1374*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
1375*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
1376*3ac0a46fSAndroid Build Coastguard Worker }
1377*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,RemoveMarks)1378*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, RemoveMarks) {
1379*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text.
1380*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
1381*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
1382*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
1383*3ac0a46fSAndroid Build Coastguard Worker 
1384*3ac0a46fSAndroid Build Coastguard Worker   constexpr int kExpectedObjectCount = 19;
1385*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
1386*3ac0a46fSAndroid Build Coastguard Worker 
1387*3ac0a46fSAndroid Build Coastguard Worker   // Remove all "Prime" content marks.
1388*3ac0a46fSAndroid Build Coastguard Worker   for (int i = 0; i < kExpectedObjectCount; ++i) {
1389*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1390*3ac0a46fSAndroid Build Coastguard Worker 
1391*3ac0a46fSAndroid Build Coastguard Worker     int mark_count = FPDFPageObj_CountMarks(page_object);
1392*3ac0a46fSAndroid Build Coastguard Worker     for (int j = mark_count - 1; j >= 0; --j) {
1393*3ac0a46fSAndroid Build Coastguard Worker       FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1394*3ac0a46fSAndroid Build Coastguard Worker 
1395*3ac0a46fSAndroid Build Coastguard Worker       char buffer[256];
1396*3ac0a46fSAndroid Build Coastguard Worker       unsigned long name_len = 999u;
1397*3ac0a46fSAndroid Build Coastguard Worker       ASSERT_TRUE(
1398*3ac0a46fSAndroid Build Coastguard Worker           FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1399*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_GT(name_len, 0u);
1400*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_NE(999u, name_len);
1401*3ac0a46fSAndroid Build Coastguard Worker       std::wstring name =
1402*3ac0a46fSAndroid Build Coastguard Worker           GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1403*3ac0a46fSAndroid Build Coastguard Worker       if (name == L"Prime") {
1404*3ac0a46fSAndroid Build Coastguard Worker         // Remove mark.
1405*3ac0a46fSAndroid Build Coastguard Worker         EXPECT_TRUE(FPDFPageObj_RemoveMark(page_object, mark));
1406*3ac0a46fSAndroid Build Coastguard Worker 
1407*3ac0a46fSAndroid Build Coastguard Worker         // Verify there is now one fewer mark in the page object.
1408*3ac0a46fSAndroid Build Coastguard Worker         EXPECT_EQ(mark_count - 1, FPDFPageObj_CountMarks(page_object));
1409*3ac0a46fSAndroid Build Coastguard Worker       }
1410*3ac0a46fSAndroid Build Coastguard Worker     }
1411*3ac0a46fSAndroid Build Coastguard Worker   }
1412*3ac0a46fSAndroid Build Coastguard Worker 
1413*3ac0a46fSAndroid Build Coastguard Worker   // Verify there are 0 "Prime" content marks now.
1414*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(page, 1, kExpectedObjectCount, 0, 4, 9, 1);
1415*3ac0a46fSAndroid Build Coastguard Worker 
1416*3ac0a46fSAndroid Build Coastguard Worker   // Save the file.
1417*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
1418*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1419*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
1420*3ac0a46fSAndroid Build Coastguard Worker 
1421*3ac0a46fSAndroid Build Coastguard Worker   // Re-open the file and check the prime marks are not there anymore.
1422*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
1423*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
1424*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
1425*3ac0a46fSAndroid Build Coastguard Worker 
1426*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(saved_page, 1, kExpectedObjectCount, 0, 4, 9, 1);
1427*3ac0a46fSAndroid Build Coastguard Worker 
1428*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
1429*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
1430*3ac0a46fSAndroid Build Coastguard Worker }
1431*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,RemoveMarkParam)1432*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, RemoveMarkParam) {
1433*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text.
1434*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
1435*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
1436*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
1437*3ac0a46fSAndroid Build Coastguard Worker 
1438*3ac0a46fSAndroid Build Coastguard Worker   constexpr int kExpectedObjectCount = 19;
1439*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
1440*3ac0a46fSAndroid Build Coastguard Worker 
1441*3ac0a46fSAndroid Build Coastguard Worker   // Remove all "Square" content marks parameters.
1442*3ac0a46fSAndroid Build Coastguard Worker   for (int i = 0; i < kExpectedObjectCount; ++i) {
1443*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1444*3ac0a46fSAndroid Build Coastguard Worker 
1445*3ac0a46fSAndroid Build Coastguard Worker     int mark_count = FPDFPageObj_CountMarks(page_object);
1446*3ac0a46fSAndroid Build Coastguard Worker     for (int j = 0; j < mark_count; ++j) {
1447*3ac0a46fSAndroid Build Coastguard Worker       FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1448*3ac0a46fSAndroid Build Coastguard Worker 
1449*3ac0a46fSAndroid Build Coastguard Worker       char buffer[256];
1450*3ac0a46fSAndroid Build Coastguard Worker       unsigned long name_len = 999u;
1451*3ac0a46fSAndroid Build Coastguard Worker       ASSERT_TRUE(
1452*3ac0a46fSAndroid Build Coastguard Worker           FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1453*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_GT(name_len, 0u);
1454*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_NE(999u, name_len);
1455*3ac0a46fSAndroid Build Coastguard Worker       std::wstring name =
1456*3ac0a46fSAndroid Build Coastguard Worker           GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1457*3ac0a46fSAndroid Build Coastguard Worker       if (name == L"Square") {
1458*3ac0a46fSAndroid Build Coastguard Worker         // Show the mark has a "Factor" parameter.
1459*3ac0a46fSAndroid Build Coastguard Worker         int out_value;
1460*3ac0a46fSAndroid Build Coastguard Worker         EXPECT_TRUE(
1461*3ac0a46fSAndroid Build Coastguard Worker             FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
1462*3ac0a46fSAndroid Build Coastguard Worker 
1463*3ac0a46fSAndroid Build Coastguard Worker         // Remove parameter.
1464*3ac0a46fSAndroid Build Coastguard Worker         EXPECT_TRUE(FPDFPageObjMark_RemoveParam(page_object, mark, "Factor"));
1465*3ac0a46fSAndroid Build Coastguard Worker 
1466*3ac0a46fSAndroid Build Coastguard Worker         // Verify the "Factor" parameter is gone.
1467*3ac0a46fSAndroid Build Coastguard Worker         EXPECT_FALSE(
1468*3ac0a46fSAndroid Build Coastguard Worker             FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
1469*3ac0a46fSAndroid Build Coastguard Worker       }
1470*3ac0a46fSAndroid Build Coastguard Worker     }
1471*3ac0a46fSAndroid Build Coastguard Worker   }
1472*3ac0a46fSAndroid Build Coastguard Worker 
1473*3ac0a46fSAndroid Build Coastguard Worker   // Save the file.
1474*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
1475*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1476*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
1477*3ac0a46fSAndroid Build Coastguard Worker 
1478*3ac0a46fSAndroid Build Coastguard Worker   // Re-open the file and check the "Factor" parameters are still gone.
1479*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
1480*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
1481*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
1482*3ac0a46fSAndroid Build Coastguard Worker 
1483*3ac0a46fSAndroid Build Coastguard Worker   size_t square_count = 0;
1484*3ac0a46fSAndroid Build Coastguard Worker   for (int i = 0; i < kExpectedObjectCount; ++i) {
1485*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(saved_page, i);
1486*3ac0a46fSAndroid Build Coastguard Worker 
1487*3ac0a46fSAndroid Build Coastguard Worker     int mark_count = FPDFPageObj_CountMarks(page_object);
1488*3ac0a46fSAndroid Build Coastguard Worker     for (int j = 0; j < mark_count; ++j) {
1489*3ac0a46fSAndroid Build Coastguard Worker       FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1490*3ac0a46fSAndroid Build Coastguard Worker 
1491*3ac0a46fSAndroid Build Coastguard Worker       char buffer[256];
1492*3ac0a46fSAndroid Build Coastguard Worker       unsigned long name_len = 999u;
1493*3ac0a46fSAndroid Build Coastguard Worker       ASSERT_TRUE(
1494*3ac0a46fSAndroid Build Coastguard Worker           FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1495*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_GT(name_len, 0u);
1496*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_NE(999u, name_len);
1497*3ac0a46fSAndroid Build Coastguard Worker       std::wstring name =
1498*3ac0a46fSAndroid Build Coastguard Worker           GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1499*3ac0a46fSAndroid Build Coastguard Worker       if (name == L"Square") {
1500*3ac0a46fSAndroid Build Coastguard Worker         // Verify the "Factor" parameter is still gone.
1501*3ac0a46fSAndroid Build Coastguard Worker         int out_value;
1502*3ac0a46fSAndroid Build Coastguard Worker         EXPECT_FALSE(
1503*3ac0a46fSAndroid Build Coastguard Worker             FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
1504*3ac0a46fSAndroid Build Coastguard Worker 
1505*3ac0a46fSAndroid Build Coastguard Worker         ++square_count;
1506*3ac0a46fSAndroid Build Coastguard Worker       }
1507*3ac0a46fSAndroid Build Coastguard Worker     }
1508*3ac0a46fSAndroid Build Coastguard Worker   }
1509*3ac0a46fSAndroid Build Coastguard Worker 
1510*3ac0a46fSAndroid Build Coastguard Worker   // Verify the parameters are gone, but the marks are not.
1511*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(4u, square_count);
1512*3ac0a46fSAndroid Build Coastguard Worker 
1513*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
1514*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
1515*3ac0a46fSAndroid Build Coastguard Worker }
1516*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,MaintainMarkedObjects)1517*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, MaintainMarkedObjects) {
1518*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text.
1519*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
1520*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
1521*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
1522*3ac0a46fSAndroid Build Coastguard Worker 
1523*3ac0a46fSAndroid Build Coastguard Worker   // Iterate over all objects, counting the number of times each content mark
1524*3ac0a46fSAndroid Build Coastguard Worker   // name appears.
1525*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
1526*3ac0a46fSAndroid Build Coastguard Worker 
1527*3ac0a46fSAndroid Build Coastguard Worker   // Remove first page object.
1528*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1529*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1530*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_Destroy(page_object);
1531*3ac0a46fSAndroid Build Coastguard Worker 
1532*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(page, 2, 18, 8, 3, 9, 1);
1533*3ac0a46fSAndroid Build Coastguard Worker 
1534*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
1535*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1536*3ac0a46fSAndroid Build Coastguard Worker 
1537*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
1538*3ac0a46fSAndroid Build Coastguard Worker 
1539*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
1540*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
1541*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
1542*3ac0a46fSAndroid Build Coastguard Worker 
1543*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(saved_page, 2, 18, 8, 3, 9, 1);
1544*3ac0a46fSAndroid Build Coastguard Worker 
1545*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
1546*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
1547*3ac0a46fSAndroid Build Coastguard Worker }
1548*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,MaintainIndirectMarkedObjects)1549*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, MaintainIndirectMarkedObjects) {
1550*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text.
1551*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("text_in_page_marked_indirect.pdf"));
1552*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
1553*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
1554*3ac0a46fSAndroid Build Coastguard Worker 
1555*3ac0a46fSAndroid Build Coastguard Worker   // Iterate over all objects, counting the number of times each content mark
1556*3ac0a46fSAndroid Build Coastguard Worker   // name appears.
1557*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
1558*3ac0a46fSAndroid Build Coastguard Worker 
1559*3ac0a46fSAndroid Build Coastguard Worker   // Remove first page object.
1560*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1561*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1562*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_Destroy(page_object);
1563*3ac0a46fSAndroid Build Coastguard Worker 
1564*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(page, 2, 18, 8, 3, 9, 1);
1565*3ac0a46fSAndroid Build Coastguard Worker 
1566*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
1567*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1568*3ac0a46fSAndroid Build Coastguard Worker 
1569*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
1570*3ac0a46fSAndroid Build Coastguard Worker 
1571*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
1572*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
1573*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
1574*3ac0a46fSAndroid Build Coastguard Worker 
1575*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(saved_page, 2, 18, 8, 3, 9, 1);
1576*3ac0a46fSAndroid Build Coastguard Worker 
1577*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
1578*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
1579*3ac0a46fSAndroid Build Coastguard Worker }
1580*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,RemoveExistingPageObject)1581*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, RemoveExistingPageObject) {
1582*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text.
1583*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("hello_world.pdf"));
1584*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
1585*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
1586*3ac0a46fSAndroid Build Coastguard Worker 
1587*3ac0a46fSAndroid Build Coastguard Worker   // Get the "Hello, world!" text object and remove it.
1588*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPage_CountObjects(page));
1589*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1590*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page_object);
1591*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1592*3ac0a46fSAndroid Build Coastguard Worker 
1593*3ac0a46fSAndroid Build Coastguard Worker   // Verify the "Hello, world!" text is gone.
1594*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFPage_CountObjects(page));
1595*3ac0a46fSAndroid Build Coastguard Worker 
1596*3ac0a46fSAndroid Build Coastguard Worker   // Save the file
1597*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
1598*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1599*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
1600*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_Destroy(page_object);
1601*3ac0a46fSAndroid Build Coastguard Worker 
1602*3ac0a46fSAndroid Build Coastguard Worker   // Re-open the file and check the page object count is still 1.
1603*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
1604*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
1605*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
1606*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(1, FPDFPage_CountObjects(saved_page));
1607*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
1608*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
1609*3ac0a46fSAndroid Build Coastguard Worker }
1610*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,RemoveExistingPageObjectSplitStreamsNotLonely)1611*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, RemoveExistingPageObjectSplitStreamsNotLonely) {
1612*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text.
1613*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("hello_world_split_streams.pdf"));
1614*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
1615*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
1616*3ac0a46fSAndroid Build Coastguard Worker 
1617*3ac0a46fSAndroid Build Coastguard Worker   // Get the "Hello, world!" text object and remove it. There is another object
1618*3ac0a46fSAndroid Build Coastguard Worker   // in the same stream that says "Goodbye, world!"
1619*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(3, FPDFPage_CountObjects(page));
1620*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1621*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page_object);
1622*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1623*3ac0a46fSAndroid Build Coastguard Worker 
1624*3ac0a46fSAndroid Build Coastguard Worker   // Verify the "Hello, world!" text is gone.
1625*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPage_CountObjects(page));
1626*3ac0a46fSAndroid Build Coastguard Worker   const char* hello_removed_checksum = []() {
1627*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
1628*3ac0a46fSAndroid Build Coastguard Worker       return "204c11472f5b93719487de7b9c1b1c93";
1629*3ac0a46fSAndroid Build Coastguard Worker     }
1630*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
1631*3ac0a46fSAndroid Build Coastguard Worker     return "5508c2f06d104050f74f655693e38c2c";
1632*3ac0a46fSAndroid Build Coastguard Worker #else
1633*3ac0a46fSAndroid Build Coastguard Worker     return "a8cd82499cf744e0862ca468c9d4ceb8";
1634*3ac0a46fSAndroid Build Coastguard Worker #endif
1635*3ac0a46fSAndroid Build Coastguard Worker   }();
1636*3ac0a46fSAndroid Build Coastguard Worker   {
1637*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
1638*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, hello_removed_checksum);
1639*3ac0a46fSAndroid Build Coastguard Worker   }
1640*3ac0a46fSAndroid Build Coastguard Worker 
1641*3ac0a46fSAndroid Build Coastguard Worker   // Save the file
1642*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
1643*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1644*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
1645*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_Destroy(page_object);
1646*3ac0a46fSAndroid Build Coastguard Worker 
1647*3ac0a46fSAndroid Build Coastguard Worker   // Re-open the file and check the page object count is still 2.
1648*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
1649*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
1650*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
1651*3ac0a46fSAndroid Build Coastguard Worker 
1652*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(2, FPDFPage_CountObjects(saved_page));
1653*3ac0a46fSAndroid Build Coastguard Worker   {
1654*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
1655*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, hello_removed_checksum);
1656*3ac0a46fSAndroid Build Coastguard Worker   }
1657*3ac0a46fSAndroid Build Coastguard Worker 
1658*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
1659*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
1660*3ac0a46fSAndroid Build Coastguard Worker }
1661*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,RemoveExistingPageObjectSplitStreamsLonely)1662*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, RemoveExistingPageObjectSplitStreamsLonely) {
1663*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text.
1664*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("hello_world_split_streams.pdf"));
1665*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
1666*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
1667*3ac0a46fSAndroid Build Coastguard Worker 
1668*3ac0a46fSAndroid Build Coastguard Worker   // Get the "Greetings, world!" text object and remove it. This is the only
1669*3ac0a46fSAndroid Build Coastguard Worker   // object in the stream.
1670*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(3, FPDFPage_CountObjects(page));
1671*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 2);
1672*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page_object);
1673*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1674*3ac0a46fSAndroid Build Coastguard Worker 
1675*3ac0a46fSAndroid Build Coastguard Worker   // Verify the "Greetings, world!" text is gone.
1676*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPage_CountObjects(page));
1677*3ac0a46fSAndroid Build Coastguard Worker   {
1678*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
1679*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, HelloWorldChecksum());
1680*3ac0a46fSAndroid Build Coastguard Worker   }
1681*3ac0a46fSAndroid Build Coastguard Worker 
1682*3ac0a46fSAndroid Build Coastguard Worker   // Save the file
1683*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
1684*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1685*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
1686*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_Destroy(page_object);
1687*3ac0a46fSAndroid Build Coastguard Worker 
1688*3ac0a46fSAndroid Build Coastguard Worker   // Re-open the file and check the page object count is still 2.
1689*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
1690*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
1691*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
1692*3ac0a46fSAndroid Build Coastguard Worker 
1693*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(2, FPDFPage_CountObjects(saved_page));
1694*3ac0a46fSAndroid Build Coastguard Worker   {
1695*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
1696*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, HelloWorldChecksum());
1697*3ac0a46fSAndroid Build Coastguard Worker   }
1698*3ac0a46fSAndroid Build Coastguard Worker 
1699*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
1700*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
1701*3ac0a46fSAndroid Build Coastguard Worker }
1702*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GetContentStream)1703*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GetContentStream) {
1704*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text split across streams.
1705*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("split_streams.pdf"));
1706*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
1707*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
1708*3ac0a46fSAndroid Build Coastguard Worker 
1709*3ac0a46fSAndroid Build Coastguard Worker   // Content stream 0: page objects 0-14.
1710*3ac0a46fSAndroid Build Coastguard Worker   // Content stream 1: page objects 15-17.
1711*3ac0a46fSAndroid Build Coastguard Worker   // Content stream 2: page object 18.
1712*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(19, FPDFPage_CountObjects(page));
1713*3ac0a46fSAndroid Build Coastguard Worker   for (int i = 0; i < 19; i++) {
1714*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1715*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(page_object);
1716*3ac0a46fSAndroid Build Coastguard Worker     CPDF_PageObject* cpdf_page_object =
1717*3ac0a46fSAndroid Build Coastguard Worker         CPDFPageObjectFromFPDFPageObject(page_object);
1718*3ac0a46fSAndroid Build Coastguard Worker     if (i < 15)
1719*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1720*3ac0a46fSAndroid Build Coastguard Worker     else if (i < 18)
1721*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_EQ(1, cpdf_page_object->GetContentStream()) << i;
1722*3ac0a46fSAndroid Build Coastguard Worker     else
1723*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_EQ(2, cpdf_page_object->GetContentStream()) << i;
1724*3ac0a46fSAndroid Build Coastguard Worker   }
1725*3ac0a46fSAndroid Build Coastguard Worker 
1726*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
1727*3ac0a46fSAndroid Build Coastguard Worker }
1728*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,RemoveAllFromStream)1729*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, RemoveAllFromStream) {
1730*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text split across streams.
1731*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("split_streams.pdf"));
1732*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
1733*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
1734*3ac0a46fSAndroid Build Coastguard Worker 
1735*3ac0a46fSAndroid Build Coastguard Worker   // Content stream 0: page objects 0-14.
1736*3ac0a46fSAndroid Build Coastguard Worker   // Content stream 1: page objects 15-17.
1737*3ac0a46fSAndroid Build Coastguard Worker   // Content stream 2: page object 18.
1738*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(19, FPDFPage_CountObjects(page));
1739*3ac0a46fSAndroid Build Coastguard Worker 
1740*3ac0a46fSAndroid Build Coastguard Worker   // Loop backwards because objects will being removed, which shifts the indexes
1741*3ac0a46fSAndroid Build Coastguard Worker   // after the removed position.
1742*3ac0a46fSAndroid Build Coastguard Worker   for (int i = 18; i >= 0; i--) {
1743*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1744*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(page_object);
1745*3ac0a46fSAndroid Build Coastguard Worker     CPDF_PageObject* cpdf_page_object =
1746*3ac0a46fSAndroid Build Coastguard Worker         CPDFPageObjectFromFPDFPageObject(page_object);
1747*3ac0a46fSAndroid Build Coastguard Worker 
1748*3ac0a46fSAndroid Build Coastguard Worker     // Empty content stream 1.
1749*3ac0a46fSAndroid Build Coastguard Worker     if (cpdf_page_object->GetContentStream() == 1) {
1750*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1751*3ac0a46fSAndroid Build Coastguard Worker       FPDFPageObj_Destroy(page_object);
1752*3ac0a46fSAndroid Build Coastguard Worker     }
1753*3ac0a46fSAndroid Build Coastguard Worker   }
1754*3ac0a46fSAndroid Build Coastguard Worker 
1755*3ac0a46fSAndroid Build Coastguard Worker   // Content stream 0: page objects 0-14.
1756*3ac0a46fSAndroid Build Coastguard Worker   // Content stream 2: page object 15.
1757*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(16, FPDFPage_CountObjects(page));
1758*3ac0a46fSAndroid Build Coastguard Worker   for (int i = 0; i < 16; i++) {
1759*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1760*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(page_object);
1761*3ac0a46fSAndroid Build Coastguard Worker     CPDF_PageObject* cpdf_page_object =
1762*3ac0a46fSAndroid Build Coastguard Worker         CPDFPageObjectFromFPDFPageObject(page_object);
1763*3ac0a46fSAndroid Build Coastguard Worker     if (i < 15)
1764*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1765*3ac0a46fSAndroid Build Coastguard Worker     else
1766*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_EQ(2, cpdf_page_object->GetContentStream()) << i;
1767*3ac0a46fSAndroid Build Coastguard Worker   }
1768*3ac0a46fSAndroid Build Coastguard Worker 
1769*3ac0a46fSAndroid Build Coastguard Worker   // Generate contents should remove the empty stream and update the page
1770*3ac0a46fSAndroid Build Coastguard Worker   // objects' contents stream indexes.
1771*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
1772*3ac0a46fSAndroid Build Coastguard Worker 
1773*3ac0a46fSAndroid Build Coastguard Worker   // Content stream 0: page objects 0-14.
1774*3ac0a46fSAndroid Build Coastguard Worker   // Content stream 1: page object 15.
1775*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(16, FPDFPage_CountObjects(page));
1776*3ac0a46fSAndroid Build Coastguard Worker   for (int i = 0; i < 16; i++) {
1777*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1778*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(page_object);
1779*3ac0a46fSAndroid Build Coastguard Worker     CPDF_PageObject* cpdf_page_object =
1780*3ac0a46fSAndroid Build Coastguard Worker         CPDFPageObjectFromFPDFPageObject(page_object);
1781*3ac0a46fSAndroid Build Coastguard Worker     if (i < 15)
1782*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1783*3ac0a46fSAndroid Build Coastguard Worker     else
1784*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_EQ(1, cpdf_page_object->GetContentStream()) << i;
1785*3ac0a46fSAndroid Build Coastguard Worker   }
1786*3ac0a46fSAndroid Build Coastguard Worker 
1787*3ac0a46fSAndroid Build Coastguard Worker   const char* stream1_removed_checksum = []() {
1788*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
1789*3ac0a46fSAndroid Build Coastguard Worker       return "0b3ef335b8d86a3f9d609368b9d075e0";
1790*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
1791*3ac0a46fSAndroid Build Coastguard Worker #if ARCH_CPU_ARM64
1792*3ac0a46fSAndroid Build Coastguard Worker     return "08505db7b598f7397a2260ecb1f6d86d";
1793*3ac0a46fSAndroid Build Coastguard Worker #else
1794*3ac0a46fSAndroid Build Coastguard Worker     return "3cdc75af44c15bed80998facd6e674c9";
1795*3ac0a46fSAndroid Build Coastguard Worker #endif  // ARCH_CPU_ARM64
1796*3ac0a46fSAndroid Build Coastguard Worker #else
1797*3ac0a46fSAndroid Build Coastguard Worker     return "b474826df1acedb05c7b82e1e49e64a6";
1798*3ac0a46fSAndroid Build Coastguard Worker #endif  // BUILDFLAG(IS_APPLE)
1799*3ac0a46fSAndroid Build Coastguard Worker   }();
1800*3ac0a46fSAndroid Build Coastguard Worker   {
1801*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
1802*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, stream1_removed_checksum);
1803*3ac0a46fSAndroid Build Coastguard Worker   }
1804*3ac0a46fSAndroid Build Coastguard Worker 
1805*3ac0a46fSAndroid Build Coastguard Worker   // Save the file
1806*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1807*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
1808*3ac0a46fSAndroid Build Coastguard Worker 
1809*3ac0a46fSAndroid Build Coastguard Worker   // Re-open the file and check the page object count is still 16, and that
1810*3ac0a46fSAndroid Build Coastguard Worker   // content stream 1 was removed.
1811*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
1812*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
1813*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
1814*3ac0a46fSAndroid Build Coastguard Worker 
1815*3ac0a46fSAndroid Build Coastguard Worker   // Content stream 0: page objects 0-14.
1816*3ac0a46fSAndroid Build Coastguard Worker   // Content stream 1: page object 15.
1817*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(16, FPDFPage_CountObjects(saved_page));
1818*3ac0a46fSAndroid Build Coastguard Worker   for (int i = 0; i < 16; i++) {
1819*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(saved_page, i);
1820*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(page_object);
1821*3ac0a46fSAndroid Build Coastguard Worker     CPDF_PageObject* cpdf_page_object =
1822*3ac0a46fSAndroid Build Coastguard Worker         CPDFPageObjectFromFPDFPageObject(page_object);
1823*3ac0a46fSAndroid Build Coastguard Worker     if (i < 15)
1824*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1825*3ac0a46fSAndroid Build Coastguard Worker     else
1826*3ac0a46fSAndroid Build Coastguard Worker       EXPECT_EQ(1, cpdf_page_object->GetContentStream()) << i;
1827*3ac0a46fSAndroid Build Coastguard Worker   }
1828*3ac0a46fSAndroid Build Coastguard Worker 
1829*3ac0a46fSAndroid Build Coastguard Worker   {
1830*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
1831*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, stream1_removed_checksum);
1832*3ac0a46fSAndroid Build Coastguard Worker   }
1833*3ac0a46fSAndroid Build Coastguard Worker 
1834*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
1835*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
1836*3ac0a46fSAndroid Build Coastguard Worker }
1837*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,RemoveAllFromSingleStream)1838*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, RemoveAllFromSingleStream) {
1839*3ac0a46fSAndroid Build Coastguard Worker   // Load document with a single stream.
1840*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("hello_world.pdf"));
1841*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
1842*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
1843*3ac0a46fSAndroid Build Coastguard Worker 
1844*3ac0a46fSAndroid Build Coastguard Worker   // Content stream 0: page objects 0-1.
1845*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPage_CountObjects(page));
1846*3ac0a46fSAndroid Build Coastguard Worker 
1847*3ac0a46fSAndroid Build Coastguard Worker   // Loop backwards because objects will being removed, which shifts the indexes
1848*3ac0a46fSAndroid Build Coastguard Worker   // after the removed position.
1849*3ac0a46fSAndroid Build Coastguard Worker   for (int i = 1; i >= 0; i--) {
1850*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1851*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(page_object);
1852*3ac0a46fSAndroid Build Coastguard Worker     CPDF_PageObject* cpdf_page_object =
1853*3ac0a46fSAndroid Build Coastguard Worker         CPDFPageObjectFromFPDFPageObject(page_object);
1854*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1855*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
1856*3ac0a46fSAndroid Build Coastguard Worker     FPDFPageObj_Destroy(page_object);
1857*3ac0a46fSAndroid Build Coastguard Worker   }
1858*3ac0a46fSAndroid Build Coastguard Worker 
1859*3ac0a46fSAndroid Build Coastguard Worker   // No more objects in the stream
1860*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(0, FPDFPage_CountObjects(page));
1861*3ac0a46fSAndroid Build Coastguard Worker 
1862*3ac0a46fSAndroid Build Coastguard Worker   // Generate contents should remove the empty stream and update the page
1863*3ac0a46fSAndroid Build Coastguard Worker   // objects' contents stream indexes.
1864*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
1865*3ac0a46fSAndroid Build Coastguard Worker 
1866*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(0, FPDFPage_CountObjects(page));
1867*3ac0a46fSAndroid Build Coastguard Worker 
1868*3ac0a46fSAndroid Build Coastguard Worker   {
1869*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
1870*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedChecksum);
1871*3ac0a46fSAndroid Build Coastguard Worker   }
1872*3ac0a46fSAndroid Build Coastguard Worker 
1873*3ac0a46fSAndroid Build Coastguard Worker   // Save the file
1874*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1875*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
1876*3ac0a46fSAndroid Build Coastguard Worker 
1877*3ac0a46fSAndroid Build Coastguard Worker   // Re-open the file and check the page object count is still 0.
1878*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
1879*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
1880*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
1881*3ac0a46fSAndroid Build Coastguard Worker 
1882*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(0, FPDFPage_CountObjects(saved_page));
1883*3ac0a46fSAndroid Build Coastguard Worker   {
1884*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
1885*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedChecksum);
1886*3ac0a46fSAndroid Build Coastguard Worker   }
1887*3ac0a46fSAndroid Build Coastguard Worker 
1888*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
1889*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
1890*3ac0a46fSAndroid Build Coastguard Worker }
1891*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,RemoveFirstFromSingleStream)1892*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, RemoveFirstFromSingleStream) {
1893*3ac0a46fSAndroid Build Coastguard Worker   // Load document with a single stream.
1894*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("hello_world.pdf"));
1895*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
1896*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
1897*3ac0a46fSAndroid Build Coastguard Worker 
1898*3ac0a46fSAndroid Build Coastguard Worker   // Content stream 0: page objects 0-1.
1899*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPage_CountObjects(page));
1900*3ac0a46fSAndroid Build Coastguard Worker 
1901*3ac0a46fSAndroid Build Coastguard Worker   // Remove first object.
1902*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1903*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page_object);
1904*3ac0a46fSAndroid Build Coastguard Worker   CPDF_PageObject* cpdf_page_object =
1905*3ac0a46fSAndroid Build Coastguard Worker       CPDFPageObjectFromFPDFPageObject(page_object);
1906*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1907*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
1908*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_Destroy(page_object);
1909*3ac0a46fSAndroid Build Coastguard Worker 
1910*3ac0a46fSAndroid Build Coastguard Worker   // One object left in the stream.
1911*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFPage_CountObjects(page));
1912*3ac0a46fSAndroid Build Coastguard Worker   page_object = FPDFPage_GetObject(page, 0);
1913*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page_object);
1914*3ac0a46fSAndroid Build Coastguard Worker   cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1915*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1916*3ac0a46fSAndroid Build Coastguard Worker 
1917*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
1918*3ac0a46fSAndroid Build Coastguard Worker 
1919*3ac0a46fSAndroid Build Coastguard Worker   // Still one object left in the stream.
1920*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFPage_CountObjects(page));
1921*3ac0a46fSAndroid Build Coastguard Worker   page_object = FPDFPage_GetObject(page, 0);
1922*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page_object);
1923*3ac0a46fSAndroid Build Coastguard Worker   cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1924*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1925*3ac0a46fSAndroid Build Coastguard Worker 
1926*3ac0a46fSAndroid Build Coastguard Worker   {
1927*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
1928*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, FirstRemovedChecksum());
1929*3ac0a46fSAndroid Build Coastguard Worker   }
1930*3ac0a46fSAndroid Build Coastguard Worker 
1931*3ac0a46fSAndroid Build Coastguard Worker   // Save the file
1932*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1933*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
1934*3ac0a46fSAndroid Build Coastguard Worker 
1935*3ac0a46fSAndroid Build Coastguard Worker   // Re-open the file and check the page object count is still 0.
1936*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
1937*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
1938*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
1939*3ac0a46fSAndroid Build Coastguard Worker 
1940*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFPage_CountObjects(saved_page));
1941*3ac0a46fSAndroid Build Coastguard Worker   page_object = FPDFPage_GetObject(saved_page, 0);
1942*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page_object);
1943*3ac0a46fSAndroid Build Coastguard Worker   cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1944*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1945*3ac0a46fSAndroid Build Coastguard Worker   {
1946*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
1947*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, FirstRemovedChecksum());
1948*3ac0a46fSAndroid Build Coastguard Worker   }
1949*3ac0a46fSAndroid Build Coastguard Worker 
1950*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
1951*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
1952*3ac0a46fSAndroid Build Coastguard Worker }
1953*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,RemoveLastFromSingleStream)1954*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, RemoveLastFromSingleStream) {
1955*3ac0a46fSAndroid Build Coastguard Worker   // Load document with a single stream.
1956*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("hello_world.pdf"));
1957*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
1958*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
1959*3ac0a46fSAndroid Build Coastguard Worker 
1960*3ac0a46fSAndroid Build Coastguard Worker   // Content stream 0: page objects 0-1.
1961*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPage_CountObjects(page));
1962*3ac0a46fSAndroid Build Coastguard Worker 
1963*3ac0a46fSAndroid Build Coastguard Worker   // Remove last object
1964*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 1);
1965*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page_object);
1966*3ac0a46fSAndroid Build Coastguard Worker   CPDF_PageObject* cpdf_page_object =
1967*3ac0a46fSAndroid Build Coastguard Worker       CPDFPageObjectFromFPDFPageObject(page_object);
1968*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1969*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
1970*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_Destroy(page_object);
1971*3ac0a46fSAndroid Build Coastguard Worker 
1972*3ac0a46fSAndroid Build Coastguard Worker   // One object left in the stream.
1973*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFPage_CountObjects(page));
1974*3ac0a46fSAndroid Build Coastguard Worker   page_object = FPDFPage_GetObject(page, 0);
1975*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page_object);
1976*3ac0a46fSAndroid Build Coastguard Worker   cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1977*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1978*3ac0a46fSAndroid Build Coastguard Worker 
1979*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
1980*3ac0a46fSAndroid Build Coastguard Worker 
1981*3ac0a46fSAndroid Build Coastguard Worker   // Still one object left in the stream.
1982*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFPage_CountObjects(page));
1983*3ac0a46fSAndroid Build Coastguard Worker   page_object = FPDFPage_GetObject(page, 0);
1984*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page_object);
1985*3ac0a46fSAndroid Build Coastguard Worker   cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1986*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1987*3ac0a46fSAndroid Build Coastguard Worker 
1988*3ac0a46fSAndroid Build Coastguard Worker   using pdfium::HelloWorldRemovedChecksum;
1989*3ac0a46fSAndroid Build Coastguard Worker   {
1990*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
1991*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, HelloWorldRemovedChecksum());
1992*3ac0a46fSAndroid Build Coastguard Worker   }
1993*3ac0a46fSAndroid Build Coastguard Worker 
1994*3ac0a46fSAndroid Build Coastguard Worker   // Save the file
1995*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1996*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
1997*3ac0a46fSAndroid Build Coastguard Worker 
1998*3ac0a46fSAndroid Build Coastguard Worker   // Re-open the file and check the page object count is still 0.
1999*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
2000*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
2001*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
2002*3ac0a46fSAndroid Build Coastguard Worker 
2003*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFPage_CountObjects(saved_page));
2004*3ac0a46fSAndroid Build Coastguard Worker   page_object = FPDFPage_GetObject(saved_page, 0);
2005*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page_object);
2006*3ac0a46fSAndroid Build Coastguard Worker   cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
2007*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(0, cpdf_page_object->GetContentStream());
2008*3ac0a46fSAndroid Build Coastguard Worker   {
2009*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
2010*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, HelloWorldRemovedChecksum());
2011*3ac0a46fSAndroid Build Coastguard Worker   }
2012*3ac0a46fSAndroid Build Coastguard Worker 
2013*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
2014*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
2015*3ac0a46fSAndroid Build Coastguard Worker }
2016*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,RemoveAllFromMultipleStreams)2017*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, RemoveAllFromMultipleStreams) {
2018*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text.
2019*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("hello_world_split_streams.pdf"));
2020*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
2021*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
2022*3ac0a46fSAndroid Build Coastguard Worker 
2023*3ac0a46fSAndroid Build Coastguard Worker   // Content stream 0: page objects 0-1.
2024*3ac0a46fSAndroid Build Coastguard Worker   // Content stream 1: page object 2.
2025*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(3, FPDFPage_CountObjects(page));
2026*3ac0a46fSAndroid Build Coastguard Worker 
2027*3ac0a46fSAndroid Build Coastguard Worker   // Loop backwards because objects will being removed, which shifts the indexes
2028*3ac0a46fSAndroid Build Coastguard Worker   // after the removed position.
2029*3ac0a46fSAndroid Build Coastguard Worker   for (int i = 2; i >= 0; i--) {
2030*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
2031*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(page_object);
2032*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
2033*3ac0a46fSAndroid Build Coastguard Worker     FPDFPageObj_Destroy(page_object);
2034*3ac0a46fSAndroid Build Coastguard Worker   }
2035*3ac0a46fSAndroid Build Coastguard Worker 
2036*3ac0a46fSAndroid Build Coastguard Worker   // No more objects in the page.
2037*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(0, FPDFPage_CountObjects(page));
2038*3ac0a46fSAndroid Build Coastguard Worker 
2039*3ac0a46fSAndroid Build Coastguard Worker   // Generate contents should remove the empty streams and update the page
2040*3ac0a46fSAndroid Build Coastguard Worker   // objects' contents stream indexes.
2041*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
2042*3ac0a46fSAndroid Build Coastguard Worker 
2043*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(0, FPDFPage_CountObjects(page));
2044*3ac0a46fSAndroid Build Coastguard Worker 
2045*3ac0a46fSAndroid Build Coastguard Worker   {
2046*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
2047*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedChecksum);
2048*3ac0a46fSAndroid Build Coastguard Worker   }
2049*3ac0a46fSAndroid Build Coastguard Worker 
2050*3ac0a46fSAndroid Build Coastguard Worker   // Save the file
2051*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2052*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
2053*3ac0a46fSAndroid Build Coastguard Worker 
2054*3ac0a46fSAndroid Build Coastguard Worker   // Re-open the file and check the page object count is still 0.
2055*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
2056*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
2057*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
2058*3ac0a46fSAndroid Build Coastguard Worker 
2059*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(0, FPDFPage_CountObjects(saved_page));
2060*3ac0a46fSAndroid Build Coastguard Worker   {
2061*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
2062*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedChecksum);
2063*3ac0a46fSAndroid Build Coastguard Worker   }
2064*3ac0a46fSAndroid Build Coastguard Worker 
2065*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
2066*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
2067*3ac0a46fSAndroid Build Coastguard Worker }
2068*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,InsertPageObjectAndSave)2069*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, InsertPageObjectAndSave) {
2070*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text.
2071*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("hello_world.pdf"));
2072*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
2073*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
2074*3ac0a46fSAndroid Build Coastguard Worker 
2075*3ac0a46fSAndroid Build Coastguard Worker   // Add a red rectangle.
2076*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPage_CountObjects(page));
2077*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
2078*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
2079*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
2080*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page, red_rect);
2081*3ac0a46fSAndroid Build Coastguard Worker 
2082*3ac0a46fSAndroid Build Coastguard Worker   // Verify the red rectangle was added.
2083*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(3, FPDFPage_CountObjects(page));
2084*3ac0a46fSAndroid Build Coastguard Worker 
2085*3ac0a46fSAndroid Build Coastguard Worker   // Save the file
2086*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
2087*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2088*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
2089*3ac0a46fSAndroid Build Coastguard Worker 
2090*3ac0a46fSAndroid Build Coastguard Worker   // Re-open the file and check the page object count is still 3.
2091*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
2092*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
2093*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
2094*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(3, FPDFPage_CountObjects(saved_page));
2095*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
2096*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
2097*3ac0a46fSAndroid Build Coastguard Worker }
2098*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,InsertPageObjectEditAndSave)2099*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, InsertPageObjectEditAndSave) {
2100*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text.
2101*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("hello_world.pdf"));
2102*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
2103*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
2104*3ac0a46fSAndroid Build Coastguard Worker 
2105*3ac0a46fSAndroid Build Coastguard Worker   // Add a red rectangle.
2106*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPage_CountObjects(page));
2107*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
2108*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 100, 100, 255));
2109*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
2110*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page, red_rect);
2111*3ac0a46fSAndroid Build Coastguard Worker 
2112*3ac0a46fSAndroid Build Coastguard Worker   // Verify the red rectangle was added.
2113*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(3, FPDFPage_CountObjects(page));
2114*3ac0a46fSAndroid Build Coastguard Worker 
2115*3ac0a46fSAndroid Build Coastguard Worker   // Generate content but change it again
2116*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
2117*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
2118*3ac0a46fSAndroid Build Coastguard Worker 
2119*3ac0a46fSAndroid Build Coastguard Worker   // Save the file
2120*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
2121*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2122*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
2123*3ac0a46fSAndroid Build Coastguard Worker 
2124*3ac0a46fSAndroid Build Coastguard Worker   // Re-open the file and check the page object count is still 3.
2125*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
2126*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
2127*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
2128*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(3, FPDFPage_CountObjects(saved_page));
2129*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
2130*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
2131*3ac0a46fSAndroid Build Coastguard Worker }
2132*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,InsertAndRemoveLargeFile)2133*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, InsertAndRemoveLargeFile) {
2134*3ac0a46fSAndroid Build Coastguard Worker   const int kOriginalObjectCount = 600;
2135*3ac0a46fSAndroid Build Coastguard Worker 
2136*3ac0a46fSAndroid Build Coastguard Worker   // Load document with many objects.
2137*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("many_rectangles.pdf"));
2138*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
2139*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
2140*3ac0a46fSAndroid Build Coastguard Worker 
2141*3ac0a46fSAndroid Build Coastguard Worker   using pdfium::ManyRectanglesChecksum;
2142*3ac0a46fSAndroid Build Coastguard Worker   {
2143*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
2144*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 300, ManyRectanglesChecksum());
2145*3ac0a46fSAndroid Build Coastguard Worker   }
2146*3ac0a46fSAndroid Build Coastguard Worker 
2147*3ac0a46fSAndroid Build Coastguard Worker   // Add a black rectangle.
2148*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(kOriginalObjectCount, FPDFPage_CountObjects(page));
2149*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT black_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
2150*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(black_rect, 0, 0, 0, 255));
2151*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_SetDrawMode(black_rect, FPDF_FILLMODE_ALTERNATE, 0));
2152*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page, black_rect);
2153*3ac0a46fSAndroid Build Coastguard Worker 
2154*3ac0a46fSAndroid Build Coastguard Worker   // Verify the black rectangle was added.
2155*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(kOriginalObjectCount + 1, FPDFPage_CountObjects(page));
2156*3ac0a46fSAndroid Build Coastguard Worker   const char* plus_rectangle_checksum = []() {
2157*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
2158*3ac0a46fSAndroid Build Coastguard Worker       return "0d3715fcfb9bd0dd25dcce60800bff47";
2159*3ac0a46fSAndroid Build Coastguard Worker     return "6b9396ab570754b32b04ca629e902f77";
2160*3ac0a46fSAndroid Build Coastguard Worker   }();
2161*3ac0a46fSAndroid Build Coastguard Worker   {
2162*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
2163*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 300, plus_rectangle_checksum);
2164*3ac0a46fSAndroid Build Coastguard Worker   }
2165*3ac0a46fSAndroid Build Coastguard Worker 
2166*3ac0a46fSAndroid Build Coastguard Worker   // Save the file.
2167*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
2168*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2169*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
2170*3ac0a46fSAndroid Build Coastguard Worker 
2171*3ac0a46fSAndroid Build Coastguard Worker   // Re-open the file and check the rectangle added is still there.
2172*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
2173*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
2174*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
2175*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(kOriginalObjectCount + 1, FPDFPage_CountObjects(saved_page));
2176*3ac0a46fSAndroid Build Coastguard Worker   {
2177*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
2178*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 300, plus_rectangle_checksum);
2179*3ac0a46fSAndroid Build Coastguard Worker   }
2180*3ac0a46fSAndroid Build Coastguard Worker 
2181*3ac0a46fSAndroid Build Coastguard Worker   // Remove the added rectangle.
2182*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT added_object =
2183*3ac0a46fSAndroid Build Coastguard Worker       FPDFPage_GetObject(saved_page, kOriginalObjectCount);
2184*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_RemoveObject(saved_page, added_object));
2185*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_Destroy(added_object);
2186*3ac0a46fSAndroid Build Coastguard Worker   {
2187*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
2188*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 300, ManyRectanglesChecksum());
2189*3ac0a46fSAndroid Build Coastguard Worker   }
2190*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(kOriginalObjectCount, FPDFPage_CountObjects(saved_page));
2191*3ac0a46fSAndroid Build Coastguard Worker 
2192*3ac0a46fSAndroid Build Coastguard Worker   // Save the file again.
2193*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(saved_page));
2194*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(saved_document(), this, 0));
2195*3ac0a46fSAndroid Build Coastguard Worker 
2196*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
2197*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
2198*3ac0a46fSAndroid Build Coastguard Worker 
2199*3ac0a46fSAndroid Build Coastguard Worker   // Re-open the file (again) and check the black rectangle was removed and the
2200*3ac0a46fSAndroid Build Coastguard Worker   // rest is intact.
2201*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
2202*3ac0a46fSAndroid Build Coastguard Worker   saved_page = LoadSavedPage(0);
2203*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
2204*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(kOriginalObjectCount, FPDFPage_CountObjects(saved_page));
2205*3ac0a46fSAndroid Build Coastguard Worker   {
2206*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
2207*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 300, ManyRectanglesChecksum());
2208*3ac0a46fSAndroid Build Coastguard Worker   }
2209*3ac0a46fSAndroid Build Coastguard Worker 
2210*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
2211*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
2212*3ac0a46fSAndroid Build Coastguard Worker }
2213*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,AddAndRemovePaths)2214*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, AddAndRemovePaths) {
2215*3ac0a46fSAndroid Build Coastguard Worker   // Start with a blank page.
2216*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
2217*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
2218*3ac0a46fSAndroid Build Coastguard Worker 
2219*3ac0a46fSAndroid Build Coastguard Worker   // Render the blank page and verify it's a blank bitmap.
2220*3ac0a46fSAndroid Build Coastguard Worker   using pdfium::kBlankPage612By792Checksum;
2221*3ac0a46fSAndroid Build Coastguard Worker   {
2222*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
2223*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792, kBlankPage612By792Checksum);
2224*3ac0a46fSAndroid Build Coastguard Worker   }
2225*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(0, FPDFPage_CountObjects(page));
2226*3ac0a46fSAndroid Build Coastguard Worker 
2227*3ac0a46fSAndroid Build Coastguard Worker   // Add a red rectangle.
2228*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
2229*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(red_rect);
2230*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
2231*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
2232*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page, red_rect);
2233*3ac0a46fSAndroid Build Coastguard Worker   {
2234*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
2235*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792, kRedRectangleChecksum);
2236*3ac0a46fSAndroid Build Coastguard Worker   }
2237*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(1, FPDFPage_CountObjects(page));
2238*3ac0a46fSAndroid Build Coastguard Worker 
2239*3ac0a46fSAndroid Build Coastguard Worker   // Remove rectangle and verify it does not render anymore and the bitmap is
2240*3ac0a46fSAndroid Build Coastguard Worker   // back to a blank one.
2241*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_RemoveObject(page, red_rect));
2242*3ac0a46fSAndroid Build Coastguard Worker   {
2243*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
2244*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792, kBlankPage612By792Checksum);
2245*3ac0a46fSAndroid Build Coastguard Worker   }
2246*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(0, FPDFPage_CountObjects(page));
2247*3ac0a46fSAndroid Build Coastguard Worker 
2248*3ac0a46fSAndroid Build Coastguard Worker   // Trying to remove an object not in the page should return false.
2249*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPage_RemoveObject(page, red_rect));
2250*3ac0a46fSAndroid Build Coastguard Worker 
2251*3ac0a46fSAndroid Build Coastguard Worker   FPDF_ClosePage(page);
2252*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_Destroy(red_rect);
2253*3ac0a46fSAndroid Build Coastguard Worker }
2254*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,PathsPoints)2255*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, PathsPoints) {
2256*3ac0a46fSAndroid Build Coastguard Worker   CreateNewDocument();
2257*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT img = FPDFPageObj_NewImageObj(document());
2258*3ac0a46fSAndroid Build Coastguard Worker   // This should fail gracefully, even if img is not a path.
2259*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(-1, FPDFPath_CountSegments(img));
2260*3ac0a46fSAndroid Build Coastguard Worker 
2261*3ac0a46fSAndroid Build Coastguard Worker   // This should fail gracefully, even if path is NULL.
2262*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(-1, FPDFPath_CountSegments(nullptr));
2263*3ac0a46fSAndroid Build Coastguard Worker 
2264*3ac0a46fSAndroid Build Coastguard Worker   // FPDFPath_GetPathSegment() with a non-path.
2265*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(nullptr, FPDFPath_GetPathSegment(img, 0));
2266*3ac0a46fSAndroid Build Coastguard Worker   // FPDFPath_GetPathSegment() with a NULL path.
2267*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(nullptr, FPDFPath_GetPathSegment(nullptr, 0));
2268*3ac0a46fSAndroid Build Coastguard Worker   float x;
2269*3ac0a46fSAndroid Build Coastguard Worker   float y;
2270*3ac0a46fSAndroid Build Coastguard Worker   // FPDFPathSegment_GetPoint() with a NULL segment.
2271*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPathSegment_GetPoint(nullptr, &x, &y));
2272*3ac0a46fSAndroid Build Coastguard Worker 
2273*3ac0a46fSAndroid Build Coastguard Worker   // FPDFPathSegment_GetType() with a NULL segment.
2274*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_SEGMENT_UNKNOWN, FPDFPathSegment_GetType(nullptr));
2275*3ac0a46fSAndroid Build Coastguard Worker 
2276*3ac0a46fSAndroid Build Coastguard Worker   // FPDFPathSegment_GetClose() with a NULL segment.
2277*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPathSegment_GetClose(nullptr));
2278*3ac0a46fSAndroid Build Coastguard Worker 
2279*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_Destroy(img);
2280*3ac0a46fSAndroid Build Coastguard Worker }
2281*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,PathOnTopOfText)2282*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, PathOnTopOfText) {
2283*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text
2284*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("hello_world.pdf"));
2285*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
2286*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
2287*3ac0a46fSAndroid Build Coastguard Worker 
2288*3ac0a46fSAndroid Build Coastguard Worker   // Add an opaque rectangle on top of some of the text.
2289*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
2290*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
2291*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
2292*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page, red_rect);
2293*3ac0a46fSAndroid Build Coastguard Worker 
2294*3ac0a46fSAndroid Build Coastguard Worker   // Add a transparent triangle on top of other part of the text.
2295*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(20, 50);
2296*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(black_path, 0, 0, 0, 100));
2297*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
2298*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_LineTo(black_path, 30, 80));
2299*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_LineTo(black_path, 40, 10));
2300*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_Close(black_path));
2301*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page, black_path);
2302*3ac0a46fSAndroid Build Coastguard Worker 
2303*3ac0a46fSAndroid Build Coastguard Worker   // Render and check the result.
2304*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
2305*3ac0a46fSAndroid Build Coastguard Worker   const char* checksum = []() {
2306*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
2307*3ac0a46fSAndroid Build Coastguard Worker       return "72523cfac069f8a81057164682998961";
2308*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
2309*3ac0a46fSAndroid Build Coastguard Worker     return "279693baca9f48da2d75a8e289aed58e";
2310*3ac0a46fSAndroid Build Coastguard Worker #else
2311*3ac0a46fSAndroid Build Coastguard Worker     return "fe415d47945c10b9cc8e9ca08887369e";
2312*3ac0a46fSAndroid Build Coastguard Worker #endif
2313*3ac0a46fSAndroid Build Coastguard Worker   }();
2314*3ac0a46fSAndroid Build Coastguard Worker   CompareBitmap(bitmap.get(), 200, 200, checksum);
2315*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
2316*3ac0a46fSAndroid Build Coastguard Worker }
2317*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,EditOverExistingContent)2318*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, EditOverExistingContent) {
2319*3ac0a46fSAndroid Build Coastguard Worker   // Load document with existing content
2320*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("bug_717.pdf"));
2321*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
2322*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
2323*3ac0a46fSAndroid Build Coastguard Worker 
2324*3ac0a46fSAndroid Build Coastguard Worker   // Add a transparent rectangle on top of the existing content
2325*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT red_rect2 = FPDFPageObj_CreateNewRect(90, 700, 25, 50);
2326*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect2, 255, 0, 0, 100));
2327*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect2, FPDF_FILLMODE_ALTERNATE, 0));
2328*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page, red_rect2);
2329*3ac0a46fSAndroid Build Coastguard Worker 
2330*3ac0a46fSAndroid Build Coastguard Worker   // Add an opaque rectangle on top of the existing content
2331*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(115, 700, 25, 50);
2332*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
2333*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
2334*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page, red_rect);
2335*3ac0a46fSAndroid Build Coastguard Worker 
2336*3ac0a46fSAndroid Build Coastguard Worker   const char* original_checksum = []() {
2337*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
2338*3ac0a46fSAndroid Build Coastguard Worker       return "1e82fbdd21490cee9d3479fe6125af67";
2339*3ac0a46fSAndroid Build Coastguard Worker     return "ad04e5bd0f471a9a564fb034bd0fb073";
2340*3ac0a46fSAndroid Build Coastguard Worker   }();
2341*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
2342*3ac0a46fSAndroid Build Coastguard Worker   CompareBitmap(bitmap.get(), 612, 792, original_checksum);
2343*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
2344*3ac0a46fSAndroid Build Coastguard Worker 
2345*3ac0a46fSAndroid Build Coastguard Worker   // Now save the result, closing the page and document
2346*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2347*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
2348*3ac0a46fSAndroid Build Coastguard Worker 
2349*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
2350*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
2351*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
2352*3ac0a46fSAndroid Build Coastguard Worker   VerifySavedRendering(saved_page, 612, 792, original_checksum);
2353*3ac0a46fSAndroid Build Coastguard Worker 
2354*3ac0a46fSAndroid Build Coastguard Worker   ClearString();
2355*3ac0a46fSAndroid Build Coastguard Worker   // Add another opaque rectangle on top of the existing content
2356*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(150, 700, 25, 50);
2357*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(green_rect, 0, 255, 0, 255));
2358*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_ALTERNATE, 0));
2359*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(saved_page, green_rect);
2360*3ac0a46fSAndroid Build Coastguard Worker 
2361*3ac0a46fSAndroid Build Coastguard Worker   // Add another transparent rectangle on top of existing content
2362*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT green_rect2 = FPDFPageObj_CreateNewRect(175, 700, 25, 50);
2363*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(green_rect2, 0, 255, 0, 100));
2364*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect2, FPDF_FILLMODE_ALTERNATE, 0));
2365*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(saved_page, green_rect2);
2366*3ac0a46fSAndroid Build Coastguard Worker   const char* last_checksum = []() {
2367*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
2368*3ac0a46fSAndroid Build Coastguard Worker       return "8705d023e5fec3499d1e30cf2bcc5dc1";
2369*3ac0a46fSAndroid Build Coastguard Worker     return "4b5b00f824620f8c9b8801ebb98e1cdd";
2370*3ac0a46fSAndroid Build Coastguard Worker   }();
2371*3ac0a46fSAndroid Build Coastguard Worker   {
2372*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap new_bitmap = RenderSavedPage(saved_page);
2373*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(new_bitmap.get(), 612, 792, last_checksum);
2374*3ac0a46fSAndroid Build Coastguard Worker   }
2375*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(saved_page));
2376*3ac0a46fSAndroid Build Coastguard Worker 
2377*3ac0a46fSAndroid Build Coastguard Worker   // Now save the result, closing the page and document
2378*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(saved_document(), this, 0));
2379*3ac0a46fSAndroid Build Coastguard Worker 
2380*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
2381*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
2382*3ac0a46fSAndroid Build Coastguard Worker 
2383*3ac0a46fSAndroid Build Coastguard Worker   // Render the saved result
2384*3ac0a46fSAndroid Build Coastguard Worker   VerifySavedDocument(612, 792, last_checksum);
2385*3ac0a46fSAndroid Build Coastguard Worker }
2386*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,AddStrokedPaths)2387*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, AddStrokedPaths) {
2388*3ac0a46fSAndroid Build Coastguard Worker   // Start with a blank page
2389*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
2390*3ac0a46fSAndroid Build Coastguard Worker 
2391*3ac0a46fSAndroid Build Coastguard Worker   // Add a large stroked rectangle (fill color should not affect it).
2392*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(20, 20, 200, 400);
2393*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(rect, 255, 0, 0, 255));
2394*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetStrokeColor(rect, 0, 255, 0, 255));
2395*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetStrokeWidth(rect, 15.0f));
2396*3ac0a46fSAndroid Build Coastguard Worker 
2397*3ac0a46fSAndroid Build Coastguard Worker   float width = 0;
2398*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_GetStrokeWidth(rect, &width));
2399*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(15.0f, width);
2400*3ac0a46fSAndroid Build Coastguard Worker 
2401*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_SetDrawMode(rect, 0, 1));
2402*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page, rect);
2403*3ac0a46fSAndroid Build Coastguard Worker   {
2404*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
2405*3ac0a46fSAndroid Build Coastguard Worker     const char* checksum_1 = []() {
2406*3ac0a46fSAndroid Build Coastguard Worker       if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
2407*3ac0a46fSAndroid Build Coastguard Worker         return "1469acf60e7647ebeb8e1fb08c5d6c7a";
2408*3ac0a46fSAndroid Build Coastguard Worker       return "64bd31f862a89e0a9e505a5af6efd506";
2409*3ac0a46fSAndroid Build Coastguard Worker     }();
2410*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792, checksum_1);
2411*3ac0a46fSAndroid Build Coastguard Worker   }
2412*3ac0a46fSAndroid Build Coastguard Worker 
2413*3ac0a46fSAndroid Build Coastguard Worker   // Add crossed-checkmark
2414*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT check = FPDFPageObj_CreateNewPath(300, 500);
2415*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_LineTo(check, 400, 400));
2416*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_LineTo(check, 600, 600));
2417*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_MoveTo(check, 400, 600));
2418*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_LineTo(check, 600, 400));
2419*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetStrokeColor(check, 128, 128, 128, 180));
2420*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetStrokeWidth(check, 8.35f));
2421*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_SetDrawMode(check, 0, 1));
2422*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page, check);
2423*3ac0a46fSAndroid Build Coastguard Worker   {
2424*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
2425*3ac0a46fSAndroid Build Coastguard Worker     const char* checksum_2 = []() {
2426*3ac0a46fSAndroid Build Coastguard Worker       if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
2427*3ac0a46fSAndroid Build Coastguard Worker         return "68b3194f74abd9d471695ce1415be43f";
2428*3ac0a46fSAndroid Build Coastguard Worker       return "4b6f3b9d25c4e194821217d5016c3724";
2429*3ac0a46fSAndroid Build Coastguard Worker     }();
2430*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792, checksum_2);
2431*3ac0a46fSAndroid Build Coastguard Worker   }
2432*3ac0a46fSAndroid Build Coastguard Worker 
2433*3ac0a46fSAndroid Build Coastguard Worker   // Add stroked and filled oval-ish path.
2434*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(250, 100);
2435*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_BezierTo(path, 180, 166, 180, 233, 250, 300));
2436*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_LineTo(path, 255, 305));
2437*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_BezierTo(path, 325, 233, 325, 166, 255, 105));
2438*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_Close(path));
2439*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(path, 200, 128, 128, 100));
2440*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetStrokeColor(path, 128, 200, 128, 150));
2441*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetStrokeWidth(path, 10.5f));
2442*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_SetDrawMode(path, FPDF_FILLMODE_ALTERNATE, 1));
2443*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page, path);
2444*3ac0a46fSAndroid Build Coastguard Worker   {
2445*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
2446*3ac0a46fSAndroid Build Coastguard Worker     const char* checksum_3 = []() {
2447*3ac0a46fSAndroid Build Coastguard Worker       if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
2448*3ac0a46fSAndroid Build Coastguard Worker         return "ea784068651df2b9ba132ce9215e6780";
2449*3ac0a46fSAndroid Build Coastguard Worker       return "ff3e6a22326754944cc6e56609acd73b";
2450*3ac0a46fSAndroid Build Coastguard Worker     }();
2451*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792, checksum_3);
2452*3ac0a46fSAndroid Build Coastguard Worker   }
2453*3ac0a46fSAndroid Build Coastguard Worker   FPDF_ClosePage(page);
2454*3ac0a46fSAndroid Build Coastguard Worker }
2455*3ac0a46fSAndroid Build Coastguard Worker 
2456*3ac0a46fSAndroid Build Coastguard Worker // Tests adding text from standard font using FPDFPageObj_NewTextObj.
TEST_F(FPDFEditEmbedderTest,AddStandardFontText)2457*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, AddStandardFontText) {
2458*3ac0a46fSAndroid Build Coastguard Worker   // Start with a blank page
2459*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
2460*3ac0a46fSAndroid Build Coastguard Worker 
2461*3ac0a46fSAndroid Build Coastguard Worker   // Add some text to the page
2462*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT text_object1 =
2463*3ac0a46fSAndroid Build Coastguard Worker       FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
2464*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(text_object1);
2465*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFWideString text1 = GetFPDFWideString(kBottomText);
2466*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFText_SetText(text_object1, text1.get()));
2467*3ac0a46fSAndroid Build Coastguard Worker   static constexpr FS_MATRIX kMatrix1{1, 0, 0, 1, 20, 20};
2468*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetMatrix(text_object1, &kMatrix1));
2469*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page.get(), text_object1);
2470*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
2471*3ac0a46fSAndroid Build Coastguard Worker   {
2472*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
2473*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792, BottomTextChecksum());
2474*3ac0a46fSAndroid Build Coastguard Worker 
2475*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2476*3ac0a46fSAndroid Build Coastguard Worker     VerifySavedDocument(612, 792, BottomTextChecksum());
2477*3ac0a46fSAndroid Build Coastguard Worker   }
2478*3ac0a46fSAndroid Build Coastguard Worker 
2479*3ac0a46fSAndroid Build Coastguard Worker   // Try another font
2480*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT text_object2 =
2481*3ac0a46fSAndroid Build Coastguard Worker       FPDFPageObj_NewTextObj(document(), "TimesNewRomanBold", 15.0f);
2482*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(text_object2);
2483*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFWideString text2 =
2484*3ac0a46fSAndroid Build Coastguard Worker       GetFPDFWideString(L"Hi, I'm Bold. Times New Roman Bold.");
2485*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
2486*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 600);
2487*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page.get(), text_object2);
2488*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
2489*3ac0a46fSAndroid Build Coastguard Worker   {
2490*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
2491*3ac0a46fSAndroid Build Coastguard Worker     const char* checksum = []() {
2492*3ac0a46fSAndroid Build Coastguard Worker       if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
2493*3ac0a46fSAndroid Build Coastguard Worker         return "3fa05f8935a43a38a8923e9d5fb94365";
2494*3ac0a46fSAndroid Build Coastguard Worker       }
2495*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
2496*3ac0a46fSAndroid Build Coastguard Worker       return "983baaa1f688eff7a14b1bf91c171a1a";
2497*3ac0a46fSAndroid Build Coastguard Worker #else
2498*3ac0a46fSAndroid Build Coastguard Worker       return "161523e196eb5341604cd73e12c97922";
2499*3ac0a46fSAndroid Build Coastguard Worker #endif
2500*3ac0a46fSAndroid Build Coastguard Worker     }();
2501*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792, checksum);
2502*3ac0a46fSAndroid Build Coastguard Worker 
2503*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2504*3ac0a46fSAndroid Build Coastguard Worker     VerifySavedDocument(612, 792, checksum);
2505*3ac0a46fSAndroid Build Coastguard Worker   }
2506*3ac0a46fSAndroid Build Coastguard Worker 
2507*3ac0a46fSAndroid Build Coastguard Worker   // And some randomly transformed text
2508*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT text_object3 =
2509*3ac0a46fSAndroid Build Coastguard Worker       FPDFPageObj_NewTextObj(document(), "Courier-Bold", 20.0f);
2510*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(text_object3);
2511*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFWideString text3 = GetFPDFWideString(L"Can you read me? <:)>");
2512*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFText_SetText(text_object3, text3.get()));
2513*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_Transform(text_object3, 1, 1.5, 2, 0.5, 200, 200);
2514*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page.get(), text_object3);
2515*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
2516*3ac0a46fSAndroid Build Coastguard Worker   {
2517*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
2518*3ac0a46fSAndroid Build Coastguard Worker     const char* checksum = []() {
2519*3ac0a46fSAndroid Build Coastguard Worker       if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
2520*3ac0a46fSAndroid Build Coastguard Worker         return "63385a217934d9ee9e17ef4d7f7b2128";
2521*3ac0a46fSAndroid Build Coastguard Worker       }
2522*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
2523*3ac0a46fSAndroid Build Coastguard Worker       return "e0b3493c5c16e41d0d892ffb48e63fba";
2524*3ac0a46fSAndroid Build Coastguard Worker #else
2525*3ac0a46fSAndroid Build Coastguard Worker       return "1fbf772dca8d82b960631e6683934964";
2526*3ac0a46fSAndroid Build Coastguard Worker #endif
2527*3ac0a46fSAndroid Build Coastguard Worker     }();
2528*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792, checksum);
2529*3ac0a46fSAndroid Build Coastguard Worker 
2530*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2531*3ac0a46fSAndroid Build Coastguard Worker     VerifySavedDocument(612, 792, checksum);
2532*3ac0a46fSAndroid Build Coastguard Worker   }
2533*3ac0a46fSAndroid Build Coastguard Worker 
2534*3ac0a46fSAndroid Build Coastguard Worker   FS_MATRIX matrix;
2535*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_GetMatrix(text_object3, &matrix));
2536*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(1.0f, matrix.a);
2537*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(1.5f, matrix.b);
2538*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(2.0f, matrix.c);
2539*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.5f, matrix.d);
2540*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(200.0f, matrix.e);
2541*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(200.0f, matrix.f);
2542*3ac0a46fSAndroid Build Coastguard Worker 
2543*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFTextObj_GetFontSize(nullptr, nullptr));
2544*3ac0a46fSAndroid Build Coastguard Worker   float size = 55;
2545*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFTextObj_GetFontSize(nullptr, &size));
2546*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(55, size);
2547*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFTextObj_GetFontSize(text_object3, &size));
2548*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(20, size);
2549*3ac0a46fSAndroid Build Coastguard Worker 
2550*3ac0a46fSAndroid Build Coastguard Worker   // TODO(npm): Why are there issues with text rotated by 90 degrees?
2551*3ac0a46fSAndroid Build Coastguard Worker   // TODO(npm): FPDF_SaveAsCopy not giving the desired result after this.
2552*3ac0a46fSAndroid Build Coastguard Worker }
2553*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,AddStandardFontTextOfSizeZero)2554*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, AddStandardFontTextOfSizeZero) {
2555*3ac0a46fSAndroid Build Coastguard Worker   // Start with a blank page
2556*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
2557*3ac0a46fSAndroid Build Coastguard Worker 
2558*3ac0a46fSAndroid Build Coastguard Worker   // Add some text of size 0 to the page.
2559*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT text_object =
2560*3ac0a46fSAndroid Build Coastguard Worker       FPDFPageObj_NewTextObj(document(), "Arial", 0.0f);
2561*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(text_object);
2562*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFWideString text = GetFPDFWideString(kBottomText);
2563*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
2564*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 20, 20);
2565*3ac0a46fSAndroid Build Coastguard Worker 
2566*3ac0a46fSAndroid Build Coastguard Worker   float size = -1;  // Make sure 'size' gets changed.
2567*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFTextObj_GetFontSize(text_object, &size));
2568*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(0.0f, size);
2569*3ac0a46fSAndroid Build Coastguard Worker 
2570*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page.get(), text_object);
2571*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
2572*3ac0a46fSAndroid Build Coastguard Worker   {
2573*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
2574*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792,
2575*3ac0a46fSAndroid Build Coastguard Worker                   pdfium::kBlankPage612By792Checksum);
2576*3ac0a46fSAndroid Build Coastguard Worker 
2577*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2578*3ac0a46fSAndroid Build Coastguard Worker     VerifySavedDocument(612, 792, pdfium::kBlankPage612By792Checksum);
2579*3ac0a46fSAndroid Build Coastguard Worker   }
2580*3ac0a46fSAndroid Build Coastguard Worker }
2581*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GetTextRenderMode)2582*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GetTextRenderMode) {
2583*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("text_render_mode.pdf"));
2584*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
2585*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
2586*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPage_CountObjects(page));
2587*3ac0a46fSAndroid Build Coastguard Worker 
2588*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_TEXTRENDERMODE_UNKNOWN,
2589*3ac0a46fSAndroid Build Coastguard Worker             FPDFTextObj_GetTextRenderMode(nullptr));
2590*3ac0a46fSAndroid Build Coastguard Worker 
2591*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT fill = FPDFPage_GetObject(page, 0);
2592*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_TEXTRENDERMODE_FILL, FPDFTextObj_GetTextRenderMode(fill));
2593*3ac0a46fSAndroid Build Coastguard Worker 
2594*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT stroke = FPDFPage_GetObject(page, 1);
2595*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_TEXTRENDERMODE_STROKE, FPDFTextObj_GetTextRenderMode(stroke));
2596*3ac0a46fSAndroid Build Coastguard Worker 
2597*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
2598*3ac0a46fSAndroid Build Coastguard Worker }
2599*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,SetTextRenderMode)2600*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, SetTextRenderMode) {
2601*3ac0a46fSAndroid Build Coastguard Worker   const char* original_checksum = []() {
2602*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
2603*3ac0a46fSAndroid Build Coastguard Worker       return "48c7f21b2a1a1bbeab24cccccc131e47";
2604*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
2605*3ac0a46fSAndroid Build Coastguard Worker     return "c488514ce0fc949069ff560407edacd2";
2606*3ac0a46fSAndroid Build Coastguard Worker #else
2607*3ac0a46fSAndroid Build Coastguard Worker     return "97a4fcf3c9581e19917895631af31d41";
2608*3ac0a46fSAndroid Build Coastguard Worker #endif
2609*3ac0a46fSAndroid Build Coastguard Worker   }();
2610*3ac0a46fSAndroid Build Coastguard Worker   const char* stroke_checksum = []() {
2611*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
2612*3ac0a46fSAndroid Build Coastguard Worker       return "d16eb1bb4748eeb5fb801594da70d519";
2613*3ac0a46fSAndroid Build Coastguard Worker     return "e06ee84aeebe926e8c980b7822027e8a";
2614*3ac0a46fSAndroid Build Coastguard Worker   }();
2615*3ac0a46fSAndroid Build Coastguard Worker 
2616*3ac0a46fSAndroid Build Coastguard Worker   {
2617*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(OpenDocument("text_render_mode.pdf"));
2618*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGE page = LoadPage(0);
2619*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(page);
2620*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(2, FPDFPage_CountObjects(page));
2621*3ac0a46fSAndroid Build Coastguard Worker 
2622*3ac0a46fSAndroid Build Coastguard Worker     // Check the bitmap
2623*3ac0a46fSAndroid Build Coastguard Worker     {
2624*3ac0a46fSAndroid Build Coastguard Worker       ScopedFPDFBitmap page_bitmap = RenderPage(page);
2625*3ac0a46fSAndroid Build Coastguard Worker       CompareBitmap(page_bitmap.get(), 612, 446, original_checksum);
2626*3ac0a46fSAndroid Build Coastguard Worker     }
2627*3ac0a46fSAndroid Build Coastguard Worker 
2628*3ac0a46fSAndroid Build Coastguard Worker     // Cannot set on a null object.
2629*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_FALSE(
2630*3ac0a46fSAndroid Build Coastguard Worker         FPDFTextObj_SetTextRenderMode(nullptr, FPDF_TEXTRENDERMODE_UNKNOWN));
2631*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_FALSE(
2632*3ac0a46fSAndroid Build Coastguard Worker         FPDFTextObj_SetTextRenderMode(nullptr, FPDF_TEXTRENDERMODE_INVISIBLE));
2633*3ac0a46fSAndroid Build Coastguard Worker 
2634*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
2635*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(page_object);
2636*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(FPDF_TEXTRENDERMODE_FILL,
2637*3ac0a46fSAndroid Build Coastguard Worker               FPDFTextObj_GetTextRenderMode(page_object));
2638*3ac0a46fSAndroid Build Coastguard Worker 
2639*3ac0a46fSAndroid Build Coastguard Worker     // Cannot set UNKNOWN as a render mode.
2640*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_FALSE(FPDFTextObj_SetTextRenderMode(page_object,
2641*3ac0a46fSAndroid Build Coastguard Worker                                                FPDF_TEXTRENDERMODE_UNKNOWN));
2642*3ac0a46fSAndroid Build Coastguard Worker 
2643*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(
2644*3ac0a46fSAndroid Build Coastguard Worker         FPDFTextObj_SetTextRenderMode(page_object, FPDF_TEXTRENDERMODE_STROKE));
2645*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(FPDF_TEXTRENDERMODE_STROKE,
2646*3ac0a46fSAndroid Build Coastguard Worker               FPDFTextObj_GetTextRenderMode(page_object));
2647*3ac0a46fSAndroid Build Coastguard Worker 
2648*3ac0a46fSAndroid Build Coastguard Worker     // Check that bitmap displays changed content
2649*3ac0a46fSAndroid Build Coastguard Worker     {
2650*3ac0a46fSAndroid Build Coastguard Worker       ScopedFPDFBitmap page_bitmap = RenderPage(page);
2651*3ac0a46fSAndroid Build Coastguard Worker       CompareBitmap(page_bitmap.get(), 612, 446, stroke_checksum);
2652*3ac0a46fSAndroid Build Coastguard Worker     }
2653*3ac0a46fSAndroid Build Coastguard Worker 
2654*3ac0a46fSAndroid Build Coastguard Worker     // Save a copy.
2655*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPage_GenerateContent(page));
2656*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2657*3ac0a46fSAndroid Build Coastguard Worker 
2658*3ac0a46fSAndroid Build Coastguard Worker     UnloadPage(page);
2659*3ac0a46fSAndroid Build Coastguard Worker   }
2660*3ac0a46fSAndroid Build Coastguard Worker 
2661*3ac0a46fSAndroid Build Coastguard Worker   {
2662*3ac0a46fSAndroid Build Coastguard Worker     // Open the saved copy and render it. Check that the changed text render
2663*3ac0a46fSAndroid Build Coastguard Worker     // mode is kept in the saved copy.
2664*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(OpenSavedDocument());
2665*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGE saved_page = LoadSavedPage(0);
2666*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(saved_page);
2667*3ac0a46fSAndroid Build Coastguard Worker 
2668*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(saved_page, 0);
2669*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(page_object);
2670*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(FPDF_TEXTRENDERMODE_STROKE,
2671*3ac0a46fSAndroid Build Coastguard Worker               FPDFTextObj_GetTextRenderMode(page_object));
2672*3ac0a46fSAndroid Build Coastguard Worker 
2673*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap = RenderSavedPage(saved_page);
2674*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(bitmap.get(), 612, 446, stroke_checksum);
2675*3ac0a46fSAndroid Build Coastguard Worker 
2676*3ac0a46fSAndroid Build Coastguard Worker     CloseSavedPage(saved_page);
2677*3ac0a46fSAndroid Build Coastguard Worker     CloseSavedDocument();
2678*3ac0a46fSAndroid Build Coastguard Worker   }
2679*3ac0a46fSAndroid Build Coastguard Worker }
2680*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,TextFontProperties)2681*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, TextFontProperties) {
2682*3ac0a46fSAndroid Build Coastguard Worker   // bad object tests
2683*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFTextObj_GetFont(nullptr));
2684*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(0U, FPDFFont_GetFontName(nullptr, nullptr, 5));
2685*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(-1, FPDFFont_GetFlags(nullptr));
2686*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(-1, FPDFFont_GetWeight(nullptr));
2687*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFFont_GetItalicAngle(nullptr, nullptr));
2688*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFFont_GetAscent(nullptr, 12.f, nullptr));
2689*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFFont_GetDescent(nullptr, 12.f, nullptr));
2690*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFFont_GetGlyphWidth(nullptr, 's', 12.f, nullptr));
2691*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFFont_GetGlyphPath(nullptr, 's', 12.f));
2692*3ac0a46fSAndroid Build Coastguard Worker 
2693*3ac0a46fSAndroid Build Coastguard Worker   // good object tests
2694*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("text_font.pdf"));
2695*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
2696*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
2697*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFPage_CountObjects(page));
2698*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT text = FPDFPage_GetObject(page, 0);
2699*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(text);
2700*3ac0a46fSAndroid Build Coastguard Worker   float font_size;
2701*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFTextObj_GetFontSize(text, &font_size));
2702*3ac0a46fSAndroid Build Coastguard Worker   FPDF_FONT font = FPDFTextObj_GetFont(text);
2703*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(font);
2704*3ac0a46fSAndroid Build Coastguard Worker 
2705*3ac0a46fSAndroid Build Coastguard Worker   // null return pointer tests
2706*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFFont_GetItalicAngle(font, nullptr));
2707*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFFont_GetAscent(font, font_size, nullptr));
2708*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFFont_GetDescent(font, font_size, nullptr));
2709*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFFont_GetGlyphWidth(font, 's', font_size, nullptr));
2710*3ac0a46fSAndroid Build Coastguard Worker 
2711*3ac0a46fSAndroid Build Coastguard Worker   // correct property tests
2712*3ac0a46fSAndroid Build Coastguard Worker   {
2713*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(4, FPDFFont_GetFlags(font));
2714*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(400, FPDFFont_GetWeight(font));
2715*3ac0a46fSAndroid Build Coastguard Worker 
2716*3ac0a46fSAndroid Build Coastguard Worker     int angle;
2717*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFFont_GetItalicAngle(font, &angle));
2718*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(0, angle);
2719*3ac0a46fSAndroid Build Coastguard Worker 
2720*3ac0a46fSAndroid Build Coastguard Worker     float ascent;
2721*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFFont_GetAscent(font, font_size, &ascent));
2722*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_FLOAT_EQ(891 * font_size / 1000.0f, ascent);
2723*3ac0a46fSAndroid Build Coastguard Worker 
2724*3ac0a46fSAndroid Build Coastguard Worker     float descent;
2725*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFFont_GetDescent(font, font_size, &descent));
2726*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_FLOAT_EQ(-216 * font_size / 1000.0f, descent);
2727*3ac0a46fSAndroid Build Coastguard Worker 
2728*3ac0a46fSAndroid Build Coastguard Worker     float a12;
2729*3ac0a46fSAndroid Build Coastguard Worker     float a24;
2730*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFFont_GetGlyphWidth(font, 'a', 12.0f, &a12));
2731*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_FLOAT_EQ(a12, 5.316f);
2732*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFFont_GetGlyphWidth(font, 'a', 24.0f, &a24));
2733*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_FLOAT_EQ(a24, 10.632f);
2734*3ac0a46fSAndroid Build Coastguard Worker   }
2735*3ac0a46fSAndroid Build Coastguard Worker 
2736*3ac0a46fSAndroid Build Coastguard Worker   {
2737*3ac0a46fSAndroid Build Coastguard Worker     // FPDFFont_GetFontName() positive testing.
2738*3ac0a46fSAndroid Build Coastguard Worker     unsigned long size = FPDFFont_GetFontName(font, nullptr, 0);
2739*3ac0a46fSAndroid Build Coastguard Worker     const char kExpectedFontName[] = "Liberation Serif";
2740*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(sizeof(kExpectedFontName), size);
2741*3ac0a46fSAndroid Build Coastguard Worker     std::vector<char> font_name(size);
2742*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(size, FPDFFont_GetFontName(font, font_name.data(), size));
2743*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_STREQ(kExpectedFontName, font_name.data());
2744*3ac0a46fSAndroid Build Coastguard Worker 
2745*3ac0a46fSAndroid Build Coastguard Worker     // FPDFFont_GetFontName() negative testing.
2746*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(0U, FPDFFont_GetFontName(nullptr, nullptr, 0));
2747*3ac0a46fSAndroid Build Coastguard Worker 
2748*3ac0a46fSAndroid Build Coastguard Worker     font_name.resize(2);
2749*3ac0a46fSAndroid Build Coastguard Worker     font_name[0] = 'x';
2750*3ac0a46fSAndroid Build Coastguard Worker     font_name[1] = '\0';
2751*3ac0a46fSAndroid Build Coastguard Worker     size = FPDFFont_GetFontName(font, font_name.data(), font_name.size());
2752*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(sizeof(kExpectedFontName), size);
2753*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_STREQ("x", font_name.data());
2754*3ac0a46fSAndroid Build Coastguard Worker   }
2755*3ac0a46fSAndroid Build Coastguard Worker 
2756*3ac0a46fSAndroid Build Coastguard Worker   {
2757*3ac0a46fSAndroid Build Coastguard Worker     // FPDFFont_GetFontData() positive testing.
2758*3ac0a46fSAndroid Build Coastguard Worker     constexpr size_t kExpectedSize = 8268;
2759*3ac0a46fSAndroid Build Coastguard Worker     std::vector<uint8_t> buf;
2760*3ac0a46fSAndroid Build Coastguard Worker     size_t buf_bytes_required = 123;
2761*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(FPDFFont_GetFontData(font, nullptr, 0, &buf_bytes_required));
2762*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(kExpectedSize, buf_bytes_required);
2763*3ac0a46fSAndroid Build Coastguard Worker 
2764*3ac0a46fSAndroid Build Coastguard Worker     buf.resize(kExpectedSize);
2765*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ("495800b8e56e2d37f3bc48a1b52db952", GenerateMD5Base16(buf));
2766*3ac0a46fSAndroid Build Coastguard Worker     buf_bytes_required = 234;
2767*3ac0a46fSAndroid Build Coastguard Worker     // Test with buffer that is too small. Make sure `buf` is unchanged.
2768*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFFont_GetFontData(font, buf.data(), buf.size() - 1,
2769*3ac0a46fSAndroid Build Coastguard Worker                                      &buf_bytes_required));
2770*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ("495800b8e56e2d37f3bc48a1b52db952", GenerateMD5Base16(buf));
2771*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(kExpectedSize, buf_bytes_required);
2772*3ac0a46fSAndroid Build Coastguard Worker 
2773*3ac0a46fSAndroid Build Coastguard Worker     // Test with buffer of the correct size.
2774*3ac0a46fSAndroid Build Coastguard Worker     buf_bytes_required = 234;
2775*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFFont_GetFontData(font, buf.data(), buf.size(),
2776*3ac0a46fSAndroid Build Coastguard Worker                                      &buf_bytes_required));
2777*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ("1a67be75f719b6c476804d85bb9e4844", GenerateMD5Base16(buf));
2778*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(kExpectedSize, buf_bytes_required);
2779*3ac0a46fSAndroid Build Coastguard Worker 
2780*3ac0a46fSAndroid Build Coastguard Worker     // FPDFFont_GetFontData() negative testing.
2781*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_FALSE(FPDFFont_GetFontData(nullptr, nullptr, 0, nullptr));
2782*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_FALSE(FPDFFont_GetFontData(font, nullptr, 0, nullptr));
2783*3ac0a46fSAndroid Build Coastguard Worker 
2784*3ac0a46fSAndroid Build Coastguard Worker     buf_bytes_required = 345;
2785*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_FALSE(
2786*3ac0a46fSAndroid Build Coastguard Worker         FPDFFont_GetFontData(nullptr, nullptr, 0, &buf_bytes_required));
2787*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(345u, buf_bytes_required);
2788*3ac0a46fSAndroid Build Coastguard Worker 
2789*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_FALSE(
2790*3ac0a46fSAndroid Build Coastguard Worker         FPDFFont_GetFontData(nullptr, buf.data(), buf.size(), nullptr));
2791*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_FALSE(FPDFFont_GetFontData(font, buf.data(), buf.size(), nullptr));
2792*3ac0a46fSAndroid Build Coastguard Worker 
2793*3ac0a46fSAndroid Build Coastguard Worker     buf_bytes_required = 345;
2794*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_FALSE(FPDFFont_GetFontData(nullptr, buf.data(), buf.size(),
2795*3ac0a46fSAndroid Build Coastguard Worker                                       &buf_bytes_required));
2796*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(345u, buf_bytes_required);
2797*3ac0a46fSAndroid Build Coastguard Worker   }
2798*3ac0a46fSAndroid Build Coastguard Worker   {
2799*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(1, FPDFFont_GetIsEmbedded(font));
2800*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(-1, FPDFFont_GetIsEmbedded(nullptr));
2801*3ac0a46fSAndroid Build Coastguard Worker   }
2802*3ac0a46fSAndroid Build Coastguard Worker 
2803*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
2804*3ac0a46fSAndroid Build Coastguard Worker }
2805*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,NoEmbeddedFontData)2806*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, NoEmbeddedFontData) {
2807*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("hello_world.pdf"));
2808*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
2809*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
2810*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPage_CountObjects(page));
2811*3ac0a46fSAndroid Build Coastguard Worker 
2812*3ac0a46fSAndroid Build Coastguard Worker   // Since hello_world.pdf does not embed any font data, FPDFFont_GetFontData()
2813*3ac0a46fSAndroid Build Coastguard Worker   // will return the substitution font data. Since pdfium_embeddertest is
2814*3ac0a46fSAndroid Build Coastguard Worker   // hermetic, this first object consistently maps to Tinos-Regular.ttf.
2815*3ac0a46fSAndroid Build Coastguard Worker   constexpr size_t kTinosRegularSize = 469968;
2816*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT text = FPDFPage_GetObject(page, 0);
2817*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(text);
2818*3ac0a46fSAndroid Build Coastguard Worker   FPDF_FONT font = FPDFTextObj_GetFont(text);
2819*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(font);
2820*3ac0a46fSAndroid Build Coastguard Worker   std::vector<uint8_t> buf;
2821*3ac0a46fSAndroid Build Coastguard Worker   buf.resize(kTinosRegularSize);
2822*3ac0a46fSAndroid Build Coastguard Worker   size_t buf_bytes_required;
2823*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(
2824*3ac0a46fSAndroid Build Coastguard Worker       FPDFFont_GetFontData(font, buf.data(), buf.size(), &buf_bytes_required));
2825*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(kTinosRegularSize, buf_bytes_required);
2826*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("2b019558f2c2de0b7cbc0a6e64b20599", GenerateMD5Base16(buf));
2827*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(0, FPDFFont_GetIsEmbedded(font));
2828*3ac0a46fSAndroid Build Coastguard Worker 
2829*3ac0a46fSAndroid Build Coastguard Worker   // Similarly, the second object consistently maps to Arimo-Regular.ttf.
2830*3ac0a46fSAndroid Build Coastguard Worker   constexpr size_t kArimoRegularSize = 436180;
2831*3ac0a46fSAndroid Build Coastguard Worker   text = FPDFPage_GetObject(page, 1);
2832*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(text);
2833*3ac0a46fSAndroid Build Coastguard Worker   font = FPDFTextObj_GetFont(text);
2834*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(font);
2835*3ac0a46fSAndroid Build Coastguard Worker   buf.resize(kArimoRegularSize);
2836*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(
2837*3ac0a46fSAndroid Build Coastguard Worker       FPDFFont_GetFontData(font, buf.data(), buf.size(), &buf_bytes_required));
2838*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(kArimoRegularSize, buf_bytes_required);
2839*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("7ac02a544211773d9636e056e9da6c35", GenerateMD5Base16(buf));
2840*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(0, FPDFFont_GetIsEmbedded(font));
2841*3ac0a46fSAndroid Build Coastguard Worker 
2842*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
2843*3ac0a46fSAndroid Build Coastguard Worker }
2844*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GlyphPaths)2845*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GlyphPaths) {
2846*3ac0a46fSAndroid Build Coastguard Worker   // bad glyphpath
2847*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(-1, FPDFGlyphPath_CountGlyphSegments(nullptr));
2848*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFGlyphPath_GetGlyphPathSegment(nullptr, 1));
2849*3ac0a46fSAndroid Build Coastguard Worker 
2850*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("text_font.pdf"));
2851*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
2852*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
2853*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFPage_CountObjects(page));
2854*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT text = FPDFPage_GetObject(page, 0);
2855*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(text);
2856*3ac0a46fSAndroid Build Coastguard Worker   FPDF_FONT font = FPDFTextObj_GetFont(text);
2857*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(font);
2858*3ac0a46fSAndroid Build Coastguard Worker 
2859*3ac0a46fSAndroid Build Coastguard Worker   // bad glyph argument.
2860*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_FALSE(FPDFFont_GetGlyphPath(font, 1, 12.0f));
2861*3ac0a46fSAndroid Build Coastguard Worker 
2862*3ac0a46fSAndroid Build Coastguard Worker   // good glyphpath
2863*3ac0a46fSAndroid Build Coastguard Worker   FPDF_GLYPHPATH gpath = FPDFFont_GetGlyphPath(font, 's', 12.0f);
2864*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(gpath);
2865*3ac0a46fSAndroid Build Coastguard Worker 
2866*3ac0a46fSAndroid Build Coastguard Worker   int count = FPDFGlyphPath_CountGlyphSegments(gpath);
2867*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_GT(count, 0);
2868*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFGlyphPath_GetGlyphPathSegment(gpath, -1));
2869*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFGlyphPath_GetGlyphPathSegment(gpath, count));
2870*3ac0a46fSAndroid Build Coastguard Worker 
2871*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PATHSEGMENT segment = FPDFGlyphPath_GetGlyphPathSegment(gpath, 1);
2872*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(segment);
2873*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_SEGMENT_BEZIERTO, FPDFPathSegment_GetType(segment));
2874*3ac0a46fSAndroid Build Coastguard Worker 
2875*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
2876*3ac0a46fSAndroid Build Coastguard Worker }
2877*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,FormGetObjects)2878*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, FormGetObjects) {
2879*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("form_object.pdf"));
2880*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
2881*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
2882*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFPage_CountObjects(page));
2883*3ac0a46fSAndroid Build Coastguard Worker 
2884*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT form = FPDFPage_GetObject(page, 0);
2885*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(form));
2886*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(-1, FPDFFormObj_CountObjects(nullptr));
2887*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFFormObj_CountObjects(form));
2888*3ac0a46fSAndroid Build Coastguard Worker 
2889*3ac0a46fSAndroid Build Coastguard Worker   // FPDFFormObj_GetObject() positive testing.
2890*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT text1 = FPDFFormObj_GetObject(form, 0);
2891*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(text1);
2892*3ac0a46fSAndroid Build Coastguard Worker   float left = 0;
2893*3ac0a46fSAndroid Build Coastguard Worker   float bottom = 0;
2894*3ac0a46fSAndroid Build Coastguard Worker   float right = 0;
2895*3ac0a46fSAndroid Build Coastguard Worker   float top = 0;
2896*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFPageObj_GetBounds(text1, &left, &bottom, &right, &top));
2897*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(271, static_cast<int>(top));
2898*3ac0a46fSAndroid Build Coastguard Worker 
2899*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT text2 = FPDFFormObj_GetObject(form, 1);
2900*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(text2);
2901*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFPageObj_GetBounds(text2, &left, &bottom, &right, &top));
2902*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(221, static_cast<int>(top));
2903*3ac0a46fSAndroid Build Coastguard Worker 
2904*3ac0a46fSAndroid Build Coastguard Worker   // FPDFFormObj_GetObject() negative testing.
2905*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(nullptr, FPDFFormObj_GetObject(nullptr, 0));
2906*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(nullptr, FPDFFormObj_GetObject(form, -1));
2907*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(nullptr, FPDFFormObj_GetObject(form, 2));
2908*3ac0a46fSAndroid Build Coastguard Worker 
2909*3ac0a46fSAndroid Build Coastguard Worker   // FPDFPageObj_GetMatrix() positive testing for forms.
2910*3ac0a46fSAndroid Build Coastguard Worker   static constexpr FS_MATRIX kMatrix = {1.0f, 1.5f, 2.0f, 2.5f, 100.0f, 200.0f};
2911*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetMatrix(form, &kMatrix));
2912*3ac0a46fSAndroid Build Coastguard Worker 
2913*3ac0a46fSAndroid Build Coastguard Worker   FS_MATRIX matrix;
2914*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_GetMatrix(form, &matrix));
2915*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(kMatrix.a, matrix.a);
2916*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(kMatrix.b, matrix.b);
2917*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(kMatrix.c, matrix.c);
2918*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(kMatrix.d, matrix.d);
2919*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(kMatrix.e, matrix.e);
2920*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(kMatrix.f, matrix.f);
2921*3ac0a46fSAndroid Build Coastguard Worker 
2922*3ac0a46fSAndroid Build Coastguard Worker   // FPDFPageObj_GetMatrix() negative testing for forms.
2923*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPageObj_GetMatrix(form, nullptr));
2924*3ac0a46fSAndroid Build Coastguard Worker 
2925*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
2926*3ac0a46fSAndroid Build Coastguard Worker }
2927*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,ModifyFormObject)2928*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, ModifyFormObject) {
2929*3ac0a46fSAndroid Build Coastguard Worker   const char* orig_checksum = []() {
2930*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
2931*3ac0a46fSAndroid Build Coastguard Worker       return "1c6dae4b04fea7430a791135721eaba5";
2932*3ac0a46fSAndroid Build Coastguard Worker     }
2933*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
2934*3ac0a46fSAndroid Build Coastguard Worker     return "a637057185f50aac1aa5490f726aef95";
2935*3ac0a46fSAndroid Build Coastguard Worker #else
2936*3ac0a46fSAndroid Build Coastguard Worker     return "34a9ec0a9581a7970e073c0bcc4ca676";
2937*3ac0a46fSAndroid Build Coastguard Worker #endif
2938*3ac0a46fSAndroid Build Coastguard Worker   }();
2939*3ac0a46fSAndroid Build Coastguard Worker   const char* new_checksum = []() {
2940*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
2941*3ac0a46fSAndroid Build Coastguard Worker       return "7282fe98693c0a7ad2c1b3f3f9563977";
2942*3ac0a46fSAndroid Build Coastguard Worker     }
2943*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
2944*3ac0a46fSAndroid Build Coastguard Worker     return "8ad9d79b02b609ff734e2a2195c96e2d";
2945*3ac0a46fSAndroid Build Coastguard Worker #else
2946*3ac0a46fSAndroid Build Coastguard Worker     return "609b5632a21c886fa93182dbc290bf7a";
2947*3ac0a46fSAndroid Build Coastguard Worker #endif
2948*3ac0a46fSAndroid Build Coastguard Worker   }();
2949*3ac0a46fSAndroid Build Coastguard Worker 
2950*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("form_object.pdf"));
2951*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
2952*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
2953*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFPage_CountObjects(page));
2954*3ac0a46fSAndroid Build Coastguard Worker 
2955*3ac0a46fSAndroid Build Coastguard Worker   {
2956*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
2957*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(bitmap.get(), 62, 69, orig_checksum);
2958*3ac0a46fSAndroid Build Coastguard Worker   }
2959*3ac0a46fSAndroid Build Coastguard Worker 
2960*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT form = FPDFPage_GetObject(page, 0);
2961*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(form));
2962*3ac0a46fSAndroid Build Coastguard Worker 
2963*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_Transform(form, 0.5, 0, 0, 0.5, 0, 0);
2964*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
2965*3ac0a46fSAndroid Build Coastguard Worker 
2966*3ac0a46fSAndroid Build Coastguard Worker   {
2967*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
2968*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(bitmap.get(), 62, 69, new_checksum);
2969*3ac0a46fSAndroid Build Coastguard Worker   }
2970*3ac0a46fSAndroid Build Coastguard Worker 
2971*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2972*3ac0a46fSAndroid Build Coastguard Worker   VerifySavedDocument(62, 69, new_checksum);
2973*3ac0a46fSAndroid Build Coastguard Worker 
2974*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
2975*3ac0a46fSAndroid Build Coastguard Worker }
2976*3ac0a46fSAndroid Build Coastguard Worker 
2977*3ac0a46fSAndroid Build Coastguard Worker // Tests adding text from standard font using FPDFText_LoadStandardFont.
TEST_F(FPDFEditEmbedderTest,AddStandardFontText2)2978*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, AddStandardFontText2) {
2979*3ac0a46fSAndroid Build Coastguard Worker   // Start with a blank page
2980*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
2981*3ac0a46fSAndroid Build Coastguard Worker 
2982*3ac0a46fSAndroid Build Coastguard Worker   // Load a standard font.
2983*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), "Helvetica"));
2984*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(font);
2985*3ac0a46fSAndroid Build Coastguard Worker 
2986*3ac0a46fSAndroid Build Coastguard Worker   // Add some text to the page.
2987*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT text_object =
2988*3ac0a46fSAndroid Build Coastguard Worker       FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
2989*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(text_object);
2990*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFWideString text = GetFPDFWideString(kBottomText);
2991*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
2992*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 20, 20);
2993*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page.get(), text_object);
2994*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
2995*3ac0a46fSAndroid Build Coastguard Worker   CompareBitmap(page_bitmap.get(), 612, 792, BottomTextChecksum());
2996*3ac0a46fSAndroid Build Coastguard Worker }
2997*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,LoadStandardFonts)2998*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, LoadStandardFonts) {
2999*3ac0a46fSAndroid Build Coastguard Worker   CreateNewDocument();
3000*3ac0a46fSAndroid Build Coastguard Worker   static constexpr const char* kStandardFontNames[] = {
3001*3ac0a46fSAndroid Build Coastguard Worker       "Arial",
3002*3ac0a46fSAndroid Build Coastguard Worker       "Arial-Bold",
3003*3ac0a46fSAndroid Build Coastguard Worker       "Arial-BoldItalic",
3004*3ac0a46fSAndroid Build Coastguard Worker       "Arial-Italic",
3005*3ac0a46fSAndroid Build Coastguard Worker       "Courier",
3006*3ac0a46fSAndroid Build Coastguard Worker       "Courier-BoldOblique",
3007*3ac0a46fSAndroid Build Coastguard Worker       "Courier-Oblique",
3008*3ac0a46fSAndroid Build Coastguard Worker       "Courier-Bold",
3009*3ac0a46fSAndroid Build Coastguard Worker       "CourierNew",
3010*3ac0a46fSAndroid Build Coastguard Worker       "CourierNew-Bold",
3011*3ac0a46fSAndroid Build Coastguard Worker       "CourierNew-BoldItalic",
3012*3ac0a46fSAndroid Build Coastguard Worker       "CourierNew-Italic",
3013*3ac0a46fSAndroid Build Coastguard Worker       "Helvetica",
3014*3ac0a46fSAndroid Build Coastguard Worker       "Helvetica-Bold",
3015*3ac0a46fSAndroid Build Coastguard Worker       "Helvetica-BoldOblique",
3016*3ac0a46fSAndroid Build Coastguard Worker       "Helvetica-Oblique",
3017*3ac0a46fSAndroid Build Coastguard Worker       "Symbol",
3018*3ac0a46fSAndroid Build Coastguard Worker       "TimesNewRoman",
3019*3ac0a46fSAndroid Build Coastguard Worker       "TimesNewRoman-Bold",
3020*3ac0a46fSAndroid Build Coastguard Worker       "TimesNewRoman-BoldItalic",
3021*3ac0a46fSAndroid Build Coastguard Worker       "TimesNewRoman-Italic",
3022*3ac0a46fSAndroid Build Coastguard Worker       "ZapfDingbats"};
3023*3ac0a46fSAndroid Build Coastguard Worker   for (const char* font_name : kStandardFontNames) {
3024*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), font_name));
3025*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(font) << font_name << " should be considered a standard font.";
3026*3ac0a46fSAndroid Build Coastguard Worker   }
3027*3ac0a46fSAndroid Build Coastguard Worker   static constexpr const char* kNotStandardFontNames[] = {
3028*3ac0a46fSAndroid Build Coastguard Worker       "Abcdefg",      "ArialB",    "Arial-Style",
3029*3ac0a46fSAndroid Build Coastguard Worker       "Font Name",    "FontArial", "NotAStandardFontName",
3030*3ac0a46fSAndroid Build Coastguard Worker       "TestFontName", "Quack",     "Symbol-Italic",
3031*3ac0a46fSAndroid Build Coastguard Worker       "Zapf"};
3032*3ac0a46fSAndroid Build Coastguard Worker   for (const char* font_name : kNotStandardFontNames) {
3033*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), font_name));
3034*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_FALSE(font) << font_name
3035*3ac0a46fSAndroid Build Coastguard Worker                        << " should not be considered a standard font.";
3036*3ac0a46fSAndroid Build Coastguard Worker   }
3037*3ac0a46fSAndroid Build Coastguard Worker }
3038*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GraphicsData)3039*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GraphicsData) {
3040*3ac0a46fSAndroid Build Coastguard Worker   // New page
3041*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
3042*3ac0a46fSAndroid Build Coastguard Worker 
3043*3ac0a46fSAndroid Build Coastguard Worker   // Create a rect with nontrivial graphics
3044*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT rect1 = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
3045*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_SetBlendMode(rect1, "Color");
3046*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page.get(), rect1);
3047*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
3048*3ac0a46fSAndroid Build Coastguard Worker 
3049*3ac0a46fSAndroid Build Coastguard Worker   // Check that the ExtGState was created
3050*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Page* cpage = CPDFPageFromFPDFPage(page.get());
3051*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Dictionary> graphics_dict =
3052*3ac0a46fSAndroid Build Coastguard Worker       cpage->GetResources()->GetDictFor("ExtGState");
3053*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(graphics_dict);
3054*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_THAT(graphics_dict->GetKeys(),
3055*3ac0a46fSAndroid Build Coastguard Worker               UnorderedElementsAreArray({"FXE1", "FXE2"}));
3056*3ac0a46fSAndroid Build Coastguard Worker 
3057*3ac0a46fSAndroid Build Coastguard Worker   // Add a text object causing no change to the graphics dictionary
3058*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT text1 = FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
3059*3ac0a46fSAndroid Build Coastguard Worker   // Only alpha, the last component, matters for the graphics dictionary. And
3060*3ac0a46fSAndroid Build Coastguard Worker   // the default value is 255.
3061*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(text1, 100, 100, 100, 255));
3062*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page.get(), text1);
3063*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
3064*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_THAT(graphics_dict->GetKeys(),
3065*3ac0a46fSAndroid Build Coastguard Worker               UnorderedElementsAreArray({"FXE1", "FXE2"}));
3066*3ac0a46fSAndroid Build Coastguard Worker 
3067*3ac0a46fSAndroid Build Coastguard Worker   // Add a text object increasing the size of the graphics dictionary
3068*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT text2 =
3069*3ac0a46fSAndroid Build Coastguard Worker       FPDFPageObj_NewTextObj(document(), "Times-Roman", 12.0f);
3070*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page.get(), text2);
3071*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_SetBlendMode(text2, "Darken");
3072*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(text2, 0, 0, 255, 150));
3073*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
3074*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_THAT(graphics_dict->GetKeys(),
3075*3ac0a46fSAndroid Build Coastguard Worker               UnorderedElementsAreArray({"FXE1", "FXE2", "FXE3"}));
3076*3ac0a46fSAndroid Build Coastguard Worker 
3077*3ac0a46fSAndroid Build Coastguard Worker   // Add a path that should reuse graphics
3078*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(400, 100);
3079*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_SetBlendMode(path, "Darken");
3080*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(path, 200, 200, 100, 150));
3081*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page.get(), path);
3082*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
3083*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_THAT(graphics_dict->GetKeys(),
3084*3ac0a46fSAndroid Build Coastguard Worker               UnorderedElementsAreArray({"FXE1", "FXE2", "FXE3"}));
3085*3ac0a46fSAndroid Build Coastguard Worker 
3086*3ac0a46fSAndroid Build Coastguard Worker   // Add a rect increasing the size of the graphics dictionary
3087*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT rect2 = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
3088*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_SetBlendMode(rect2, "Darken");
3089*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(rect2, 0, 0, 255, 150));
3090*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetStrokeColor(rect2, 0, 0, 0, 200));
3091*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page.get(), rect2);
3092*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
3093*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_THAT(graphics_dict->GetKeys(),
3094*3ac0a46fSAndroid Build Coastguard Worker               UnorderedElementsAreArray({"FXE1", "FXE2", "FXE3", "FXE4"}));
3095*3ac0a46fSAndroid Build Coastguard Worker }
3096*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,DoubleGenerating)3097*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, DoubleGenerating) {
3098*3ac0a46fSAndroid Build Coastguard Worker   // Start with a blank page
3099*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
3100*3ac0a46fSAndroid Build Coastguard Worker 
3101*3ac0a46fSAndroid Build Coastguard Worker   // Add a red rectangle with some non-default alpha
3102*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
3103*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(rect, 255, 0, 0, 128));
3104*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPath_SetDrawMode(rect, FPDF_FILLMODE_WINDING, 0));
3105*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page, rect);
3106*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
3107*3ac0a46fSAndroid Build Coastguard Worker 
3108*3ac0a46fSAndroid Build Coastguard Worker   // Check the ExtGState
3109*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Page* cpage = CPDFPageFromFPDFPage(page);
3110*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Dictionary> graphics_dict =
3111*3ac0a46fSAndroid Build Coastguard Worker       cpage->GetResources()->GetDictFor("ExtGState");
3112*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(graphics_dict);
3113*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_THAT(graphics_dict->GetKeys(),
3114*3ac0a46fSAndroid Build Coastguard Worker               UnorderedElementsAreArray({"FXE1", "FXE2"}));
3115*3ac0a46fSAndroid Build Coastguard Worker 
3116*3ac0a46fSAndroid Build Coastguard Worker   // Check the bitmap
3117*3ac0a46fSAndroid Build Coastguard Worker   {
3118*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
3119*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792,
3120*3ac0a46fSAndroid Build Coastguard Worker                   "5384da3406d62360ffb5cac4476fff1c");
3121*3ac0a46fSAndroid Build Coastguard Worker   }
3122*3ac0a46fSAndroid Build Coastguard Worker 
3123*3ac0a46fSAndroid Build Coastguard Worker   // Never mind, my new favorite color is blue, increase alpha.
3124*3ac0a46fSAndroid Build Coastguard Worker   // The red graphics state goes away.
3125*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetFillColor(rect, 0, 0, 255, 180));
3126*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
3127*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_THAT(graphics_dict->GetKeys(),
3128*3ac0a46fSAndroid Build Coastguard Worker               UnorderedElementsAreArray({"FXE1", "FXE3"}));
3129*3ac0a46fSAndroid Build Coastguard Worker 
3130*3ac0a46fSAndroid Build Coastguard Worker   // Check that bitmap displays changed content
3131*3ac0a46fSAndroid Build Coastguard Worker   {
3132*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
3133*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792,
3134*3ac0a46fSAndroid Build Coastguard Worker                   "2e51656f5073b0bee611d9cd086aa09c");
3135*3ac0a46fSAndroid Build Coastguard Worker   }
3136*3ac0a46fSAndroid Build Coastguard Worker 
3137*3ac0a46fSAndroid Build Coastguard Worker   // And now generate, without changes
3138*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
3139*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_THAT(graphics_dict->GetKeys(),
3140*3ac0a46fSAndroid Build Coastguard Worker               UnorderedElementsAreArray({"FXE1", "FXE3"}));
3141*3ac0a46fSAndroid Build Coastguard Worker   {
3142*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
3143*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792,
3144*3ac0a46fSAndroid Build Coastguard Worker                   "2e51656f5073b0bee611d9cd086aa09c");
3145*3ac0a46fSAndroid Build Coastguard Worker   }
3146*3ac0a46fSAndroid Build Coastguard Worker 
3147*3ac0a46fSAndroid Build Coastguard Worker   // Add some text to the page, which starts out with no fonts.
3148*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Dictionary> font_dict =
3149*3ac0a46fSAndroid Build Coastguard Worker       cpage->GetResources()->GetDictFor("Font");
3150*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(font_dict);
3151*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT text_object =
3152*3ac0a46fSAndroid Build Coastguard Worker       FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
3153*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFWideString text =
3154*3ac0a46fSAndroid Build Coastguard Worker       GetFPDFWideString(L"Something something #text# something");
3155*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
3156*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 300, 300);
3157*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page, text_object);
3158*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
3159*3ac0a46fSAndroid Build Coastguard Worker 
3160*3ac0a46fSAndroid Build Coastguard Worker   // After generating the content, there should now be a font resource.
3161*3ac0a46fSAndroid Build Coastguard Worker   font_dict = cpage->GetResources()->GetDictFor("Font");
3162*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(font_dict);
3163*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_THAT(graphics_dict->GetKeys(),
3164*3ac0a46fSAndroid Build Coastguard Worker               UnorderedElementsAreArray({"FXE1", "FXE3"}));
3165*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_THAT(font_dict->GetKeys(), UnorderedElementsAreArray({"FXF1"}));
3166*3ac0a46fSAndroid Build Coastguard Worker 
3167*3ac0a46fSAndroid Build Coastguard Worker   // Generate yet again, check dicts are reasonably sized
3168*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
3169*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_THAT(graphics_dict->GetKeys(),
3170*3ac0a46fSAndroid Build Coastguard Worker               UnorderedElementsAreArray({"FXE1", "FXE3"}));
3171*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_THAT(font_dict->GetKeys(), UnorderedElementsAreArray({"FXF1"}));
3172*3ac0a46fSAndroid Build Coastguard Worker   FPDF_ClosePage(page);
3173*3ac0a46fSAndroid Build Coastguard Worker }
3174*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,LoadSimpleType1Font)3175*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, LoadSimpleType1Font) {
3176*3ac0a46fSAndroid Build Coastguard Worker   CreateNewDocument();
3177*3ac0a46fSAndroid Build Coastguard Worker   // TODO(npm): use other fonts after disallowing loading any font as any type
3178*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Font> stock_font =
3179*3ac0a46fSAndroid Build Coastguard Worker       CPDF_Font::GetStockFont(cpdf_doc(), "Times-Bold");
3180*3ac0a46fSAndroid Build Coastguard Worker   pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
3181*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3182*3ac0a46fSAndroid Build Coastguard Worker                                         FPDF_FONT_TYPE1, false));
3183*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(font.get());
3184*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
3185*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(typed_font->IsType1Font());
3186*3ac0a46fSAndroid Build Coastguard Worker 
3187*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Dictionary> font_dict = typed_font->GetFontDict();
3188*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
3189*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Type1", font_dict->GetNameFor("Subtype"));
3190*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Tinos-Bold", font_dict->GetNameFor("BaseFont"));
3191*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
3192*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(font_dict->KeyExist("LastChar"));
3193*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
3194*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
3195*3ac0a46fSAndroid Build Coastguard Worker 
3196*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Array> widths_array = font_dict->GetArrayFor("Widths");
3197*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(widths_array);
3198*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(224u, widths_array->size());
3199*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(250, widths_array->GetFloatAt(0));
3200*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(569, widths_array->GetFloatAt(11));
3201*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(500, widths_array->GetFloatAt(223));
3202*3ac0a46fSAndroid Build Coastguard Worker   CheckFontDescriptor(font_dict, FPDF_FONT_TYPE1, true, false, span);
3203*3ac0a46fSAndroid Build Coastguard Worker }
3204*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,LoadSimpleTrueTypeFont)3205*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, LoadSimpleTrueTypeFont) {
3206*3ac0a46fSAndroid Build Coastguard Worker   CreateNewDocument();
3207*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Font> stock_font =
3208*3ac0a46fSAndroid Build Coastguard Worker       CPDF_Font::GetStockFont(cpdf_doc(), "Courier");
3209*3ac0a46fSAndroid Build Coastguard Worker   pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
3210*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3211*3ac0a46fSAndroid Build Coastguard Worker                                         FPDF_FONT_TRUETYPE, false));
3212*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(font.get());
3213*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
3214*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(typed_font->IsTrueTypeFont());
3215*3ac0a46fSAndroid Build Coastguard Worker 
3216*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Dictionary> font_dict = typed_font->GetFontDict();
3217*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
3218*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("TrueType", font_dict->GetNameFor("Subtype"));
3219*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Cousine-Regular", font_dict->GetNameFor("BaseFont"));
3220*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
3221*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(font_dict->KeyExist("LastChar"));
3222*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
3223*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
3224*3ac0a46fSAndroid Build Coastguard Worker 
3225*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Array> widths_array = font_dict->GetArrayFor("Widths");
3226*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(widths_array);
3227*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(224u, widths_array->size());
3228*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(600, widths_array->GetFloatAt(33));
3229*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(600, widths_array->GetFloatAt(74));
3230*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(600, widths_array->GetFloatAt(223));
3231*3ac0a46fSAndroid Build Coastguard Worker   CheckFontDescriptor(font_dict, FPDF_FONT_TRUETYPE, false, false, span);
3232*3ac0a46fSAndroid Build Coastguard Worker }
3233*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,LoadCIDType0Font)3234*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, LoadCIDType0Font) {
3235*3ac0a46fSAndroid Build Coastguard Worker   CreateNewDocument();
3236*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Font> stock_font =
3237*3ac0a46fSAndroid Build Coastguard Worker       CPDF_Font::GetStockFont(cpdf_doc(), "Times-Roman");
3238*3ac0a46fSAndroid Build Coastguard Worker   pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
3239*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3240*3ac0a46fSAndroid Build Coastguard Worker                                         FPDF_FONT_TYPE1, 1));
3241*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(font.get());
3242*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
3243*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(typed_font->IsCIDFont());
3244*3ac0a46fSAndroid Build Coastguard Worker 
3245*3ac0a46fSAndroid Build Coastguard Worker   // Check font dictionary entries
3246*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Dictionary> font_dict = typed_font->GetFontDict();
3247*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
3248*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Type0", font_dict->GetNameFor("Subtype"));
3249*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Tinos-Regular-Identity-H", font_dict->GetNameFor("BaseFont"));
3250*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Identity-H", font_dict->GetNameFor("Encoding"));
3251*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Array> descendant_array =
3252*3ac0a46fSAndroid Build Coastguard Worker       font_dict->GetArrayFor("DescendantFonts");
3253*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(descendant_array);
3254*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(1u, descendant_array->size());
3255*3ac0a46fSAndroid Build Coastguard Worker 
3256*3ac0a46fSAndroid Build Coastguard Worker   // Check the CIDFontDict
3257*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Dictionary> cidfont_dict =
3258*3ac0a46fSAndroid Build Coastguard Worker       descendant_array->GetDictAt(0);
3259*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Font", cidfont_dict->GetNameFor("Type"));
3260*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("CIDFontType0", cidfont_dict->GetNameFor("Subtype"));
3261*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Tinos-Regular", cidfont_dict->GetNameFor("BaseFont"));
3262*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Dictionary> cidinfo_dict =
3263*3ac0a46fSAndroid Build Coastguard Worker       cidfont_dict->GetDictFor("CIDSystemInfo");
3264*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(cidinfo_dict);
3265*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Object> registry =
3266*3ac0a46fSAndroid Build Coastguard Worker       cidinfo_dict->GetObjectFor("Registry");
3267*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(registry);
3268*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(CPDF_Object::kString, registry->GetType());
3269*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Adobe", registry->GetString());
3270*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Object> ordering =
3271*3ac0a46fSAndroid Build Coastguard Worker       cidinfo_dict->GetObjectFor("Ordering");
3272*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(ordering);
3273*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(CPDF_Object::kString, ordering->GetType());
3274*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Identity", ordering->GetString());
3275*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(0, cidinfo_dict->GetFloatFor("Supplement"));
3276*3ac0a46fSAndroid Build Coastguard Worker   CheckFontDescriptor(cidfont_dict.Get(), FPDF_FONT_TYPE1, false, false, span);
3277*3ac0a46fSAndroid Build Coastguard Worker 
3278*3ac0a46fSAndroid Build Coastguard Worker   // Check widths
3279*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Array> widths_array = cidfont_dict->GetArrayFor("W");
3280*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(widths_array);
3281*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_GT(widths_array->size(), 1u);
3282*3ac0a46fSAndroid Build Coastguard Worker   CheckCompositeFontWidths(widths_array.Get(), typed_font);
3283*3ac0a46fSAndroid Build Coastguard Worker }
3284*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,LoadCIDType2Font)3285*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, LoadCIDType2Font) {
3286*3ac0a46fSAndroid Build Coastguard Worker   CreateNewDocument();
3287*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Font> stock_font =
3288*3ac0a46fSAndroid Build Coastguard Worker       CPDF_Font::GetStockFont(cpdf_doc(), "Helvetica-Oblique");
3289*3ac0a46fSAndroid Build Coastguard Worker   pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
3290*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3291*3ac0a46fSAndroid Build Coastguard Worker                                         FPDF_FONT_TRUETYPE, 1));
3292*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(font.get());
3293*3ac0a46fSAndroid Build Coastguard Worker   CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
3294*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(typed_font->IsCIDFont());
3295*3ac0a46fSAndroid Build Coastguard Worker 
3296*3ac0a46fSAndroid Build Coastguard Worker   // Check font dictionary entries
3297*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Dictionary> font_dict = typed_font->GetFontDict();
3298*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
3299*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Type0", font_dict->GetNameFor("Subtype"));
3300*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Arimo-Italic", font_dict->GetNameFor("BaseFont"));
3301*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Identity-H", font_dict->GetNameFor("Encoding"));
3302*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Array> descendant_array =
3303*3ac0a46fSAndroid Build Coastguard Worker       font_dict->GetArrayFor("DescendantFonts");
3304*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(descendant_array);
3305*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(1u, descendant_array->size());
3306*3ac0a46fSAndroid Build Coastguard Worker 
3307*3ac0a46fSAndroid Build Coastguard Worker   // Check the CIDFontDict
3308*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Dictionary> cidfont_dict =
3309*3ac0a46fSAndroid Build Coastguard Worker       descendant_array->GetDictAt(0);
3310*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Font", cidfont_dict->GetNameFor("Type"));
3311*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("CIDFontType2", cidfont_dict->GetNameFor("Subtype"));
3312*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Arimo-Italic", cidfont_dict->GetNameFor("BaseFont"));
3313*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Dictionary> cidinfo_dict =
3314*3ac0a46fSAndroid Build Coastguard Worker       cidfont_dict->GetDictFor("CIDSystemInfo");
3315*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(cidinfo_dict);
3316*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Adobe", cidinfo_dict->GetByteStringFor("Registry"));
3317*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("Identity", cidinfo_dict->GetByteStringFor("Ordering"));
3318*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(0, cidinfo_dict->GetFloatFor("Supplement"));
3319*3ac0a46fSAndroid Build Coastguard Worker   CheckFontDescriptor(cidfont_dict.Get(), FPDF_FONT_TRUETYPE, false, true,
3320*3ac0a46fSAndroid Build Coastguard Worker                       span);
3321*3ac0a46fSAndroid Build Coastguard Worker 
3322*3ac0a46fSAndroid Build Coastguard Worker   // Check widths
3323*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<const CPDF_Array> widths_array = cidfont_dict->GetArrayFor("W");
3324*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(widths_array);
3325*3ac0a46fSAndroid Build Coastguard Worker   CheckCompositeFontWidths(widths_array.Get(), typed_font);
3326*3ac0a46fSAndroid Build Coastguard Worker }
3327*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,NormalizeNegativeRotation)3328*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, NormalizeNegativeRotation) {
3329*3ac0a46fSAndroid Build Coastguard Worker   // Load document with a -90 degree rotation
3330*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("bug_713197.pdf"));
3331*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
3332*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(page);
3333*3ac0a46fSAndroid Build Coastguard Worker 
3334*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(3, FPDFPage_GetRotation(page));
3335*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
3336*3ac0a46fSAndroid Build Coastguard Worker }
3337*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,AddTrueTypeFontText)3338*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, AddTrueTypeFontText) {
3339*3ac0a46fSAndroid Build Coastguard Worker   // Start with a blank page
3340*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
3341*3ac0a46fSAndroid Build Coastguard Worker   {
3342*3ac0a46fSAndroid Build Coastguard Worker     RetainPtr<CPDF_Font> stock_font =
3343*3ac0a46fSAndroid Build Coastguard Worker         CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
3344*3ac0a46fSAndroid Build Coastguard Worker     pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
3345*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3346*3ac0a46fSAndroid Build Coastguard Worker                                           FPDF_FONT_TRUETYPE, 0));
3347*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(font.get());
3348*3ac0a46fSAndroid Build Coastguard Worker 
3349*3ac0a46fSAndroid Build Coastguard Worker     // Add some text to the page
3350*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT text_object =
3351*3ac0a46fSAndroid Build Coastguard Worker         FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
3352*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(text_object);
3353*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFWideString text = GetFPDFWideString(kLoadedFontText);
3354*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
3355*3ac0a46fSAndroid Build Coastguard Worker     FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
3356*3ac0a46fSAndroid Build Coastguard Worker     FPDFPage_InsertObject(page, text_object);
3357*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
3358*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792, LoadedFontTextChecksum());
3359*3ac0a46fSAndroid Build Coastguard Worker 
3360*3ac0a46fSAndroid Build Coastguard Worker     // Add some more text, same font
3361*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT text_object2 =
3362*3ac0a46fSAndroid Build Coastguard Worker         FPDFPageObj_CreateTextObj(document(), font.get(), 15.0f);
3363*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFWideString text2 = GetFPDFWideString(L"Bigger font size");
3364*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
3365*3ac0a46fSAndroid Build Coastguard Worker     FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 200, 200);
3366*3ac0a46fSAndroid Build Coastguard Worker     FPDFPage_InsertObject(page, text_object2);
3367*3ac0a46fSAndroid Build Coastguard Worker   }
3368*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFBitmap page_bitmap2 = RenderPage(page);
3369*3ac0a46fSAndroid Build Coastguard Worker   const char* insert_true_type_checksum = []() {
3370*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
3371*3ac0a46fSAndroid Build Coastguard Worker       return "4f9a6c7752ac7d4e4c731260fdb5af15";
3372*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
3373*3ac0a46fSAndroid Build Coastguard Worker     return "c7e2271a7f30e5b919a13ead47cea105";
3374*3ac0a46fSAndroid Build Coastguard Worker #else
3375*3ac0a46fSAndroid Build Coastguard Worker     return "683f4a385a891494100192cb338b11f0";
3376*3ac0a46fSAndroid Build Coastguard Worker #endif
3377*3ac0a46fSAndroid Build Coastguard Worker   }();
3378*3ac0a46fSAndroid Build Coastguard Worker   CompareBitmap(page_bitmap2.get(), 612, 792, insert_true_type_checksum);
3379*3ac0a46fSAndroid Build Coastguard Worker 
3380*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
3381*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3382*3ac0a46fSAndroid Build Coastguard Worker   FPDF_ClosePage(page);
3383*3ac0a46fSAndroid Build Coastguard Worker 
3384*3ac0a46fSAndroid Build Coastguard Worker   VerifySavedDocument(612, 792, insert_true_type_checksum);
3385*3ac0a46fSAndroid Build Coastguard Worker }
3386*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,TransformAnnot)3387*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, TransformAnnot) {
3388*3ac0a46fSAndroid Build Coastguard Worker   // Open a file with one annotation and load its first page.
3389*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("annotation_highlight_long_content.pdf"));
3390*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
3391*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
3392*3ac0a46fSAndroid Build Coastguard Worker 
3393*3ac0a46fSAndroid Build Coastguard Worker   {
3394*3ac0a46fSAndroid Build Coastguard Worker     // Add an underline annotation to the page without specifying its rectangle.
3395*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFAnnotation annot(
3396*3ac0a46fSAndroid Build Coastguard Worker         FPDFPage_CreateAnnot(page, FPDF_ANNOT_UNDERLINE));
3397*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(annot);
3398*3ac0a46fSAndroid Build Coastguard Worker 
3399*3ac0a46fSAndroid Build Coastguard Worker     // FPDFPage_TransformAnnots() should run without errors when modifying
3400*3ac0a46fSAndroid Build Coastguard Worker     // annotation rectangles.
3401*3ac0a46fSAndroid Build Coastguard Worker     FPDFPage_TransformAnnots(page, 1, 2, 3, 4, 5, 6);
3402*3ac0a46fSAndroid Build Coastguard Worker   }
3403*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
3404*3ac0a46fSAndroid Build Coastguard Worker }
3405*3ac0a46fSAndroid Build Coastguard Worker 
3406*3ac0a46fSAndroid Build Coastguard Worker // TODO(npm): Add tests using Japanese fonts in other OS.
3407*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
TEST_F(FPDFEditEmbedderTest,AddCIDFontText)3408*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, AddCIDFontText) {
3409*3ac0a46fSAndroid Build Coastguard Worker   // Start with a blank page
3410*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
3411*3ac0a46fSAndroid Build Coastguard Worker   CFX_Font CIDfont;
3412*3ac0a46fSAndroid Build Coastguard Worker   {
3413*3ac0a46fSAndroid Build Coastguard Worker     // First, get the data from the font
3414*3ac0a46fSAndroid Build Coastguard Worker     CIDfont.LoadSubst("Noto Sans CJK JP", true, 0, 400, 0,
3415*3ac0a46fSAndroid Build Coastguard Worker                       FX_CodePage::kShiftJIS, false);
3416*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ("Noto Sans CJK JP", CIDfont.GetFaceName());
3417*3ac0a46fSAndroid Build Coastguard Worker     pdfium::span<const uint8_t> span = CIDfont.GetFontSpan();
3418*3ac0a46fSAndroid Build Coastguard Worker 
3419*3ac0a46fSAndroid Build Coastguard Worker     // Load the data into a FPDF_Font.
3420*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3421*3ac0a46fSAndroid Build Coastguard Worker                                           FPDF_FONT_TRUETYPE, 1));
3422*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(font.get());
3423*3ac0a46fSAndroid Build Coastguard Worker 
3424*3ac0a46fSAndroid Build Coastguard Worker     // Add some text to the page
3425*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT text_object =
3426*3ac0a46fSAndroid Build Coastguard Worker         FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
3427*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(text_object);
3428*3ac0a46fSAndroid Build Coastguard Worker     std::wstring wstr = L"ABCDEFGhijklmnop.";
3429*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFWideString text = GetFPDFWideString(wstr);
3430*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
3431*3ac0a46fSAndroid Build Coastguard Worker     FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 200, 200);
3432*3ac0a46fSAndroid Build Coastguard Worker     FPDFPage_InsertObject(page, text_object);
3433*3ac0a46fSAndroid Build Coastguard Worker 
3434*3ac0a46fSAndroid Build Coastguard Worker     // And add some Japanese characters
3435*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT text_object2 =
3436*3ac0a46fSAndroid Build Coastguard Worker         FPDFPageObj_CreateTextObj(document(), font.get(), 18.0f);
3437*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(text_object2);
3438*3ac0a46fSAndroid Build Coastguard Worker     std::wstring wstr2 =
3439*3ac0a46fSAndroid Build Coastguard Worker         L"\u3053\u3093\u306B\u3061\u306f\u4e16\u754C\u3002\u3053\u3053\u306B1"
3440*3ac0a46fSAndroid Build Coastguard Worker         L"\u756A";
3441*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFWideString text2 = GetFPDFWideString(wstr2);
3442*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
3443*3ac0a46fSAndroid Build Coastguard Worker     FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 500);
3444*3ac0a46fSAndroid Build Coastguard Worker     FPDFPage_InsertObject(page, text_object2);
3445*3ac0a46fSAndroid Build Coastguard Worker   }
3446*3ac0a46fSAndroid Build Coastguard Worker 
3447*3ac0a46fSAndroid Build Coastguard Worker   // Check that the text renders properly.
3448*3ac0a46fSAndroid Build Coastguard Worker   const char* checksum = []() {
3449*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
3450*3ac0a46fSAndroid Build Coastguard Worker       return "2e174d17de96a760d42ca3a06acbf36a";
3451*3ac0a46fSAndroid Build Coastguard Worker     }
3452*3ac0a46fSAndroid Build Coastguard Worker     return "84d31d11b76845423a2cfc1879c0fbb9";
3453*3ac0a46fSAndroid Build Coastguard Worker   }();
3454*3ac0a46fSAndroid Build Coastguard Worker 
3455*3ac0a46fSAndroid Build Coastguard Worker   {
3456*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
3457*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792, checksum);
3458*3ac0a46fSAndroid Build Coastguard Worker   }
3459*3ac0a46fSAndroid Build Coastguard Worker 
3460*3ac0a46fSAndroid Build Coastguard Worker   // Save the document, close the page.
3461*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
3462*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3463*3ac0a46fSAndroid Build Coastguard Worker   FPDF_ClosePage(page);
3464*3ac0a46fSAndroid Build Coastguard Worker 
3465*3ac0a46fSAndroid Build Coastguard Worker   VerifySavedDocument(612, 792, checksum);
3466*3ac0a46fSAndroid Build Coastguard Worker }
3467*3ac0a46fSAndroid Build Coastguard Worker #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
3468*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,SaveAndRender)3469*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, SaveAndRender) {
3470*3ac0a46fSAndroid Build Coastguard Worker   const char* checksum = []() {
3471*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
3472*3ac0a46fSAndroid Build Coastguard Worker       return "9a78649e85e69d220c22e0fc316da740";
3473*3ac0a46fSAndroid Build Coastguard Worker     return "3c20472b0552c0c22b88ab1ed8c6202b";
3474*3ac0a46fSAndroid Build Coastguard Worker   }();
3475*3ac0a46fSAndroid Build Coastguard Worker   {
3476*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(OpenDocument("bug_779.pdf"));
3477*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGE page = LoadPage(0);
3478*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_NE(nullptr, page);
3479*3ac0a46fSAndroid Build Coastguard Worker 
3480*3ac0a46fSAndroid Build Coastguard Worker     // Now add a more complex green path.
3481*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT green_path = FPDFPageObj_CreateNewPath(20, 20);
3482*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPageObj_SetFillColor(green_path, 0, 255, 0, 200));
3483*3ac0a46fSAndroid Build Coastguard Worker     // TODO(npm): stroking will cause the checksums to differ.
3484*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPath_SetDrawMode(green_path, FPDF_FILLMODE_WINDING, 0));
3485*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPath_LineTo(green_path, 20, 63));
3486*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPath_BezierTo(green_path, 55, 55, 78, 78, 90, 90));
3487*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPath_LineTo(green_path, 133, 133));
3488*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPath_LineTo(green_path, 133, 33));
3489*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPath_BezierTo(green_path, 38, 33, 39, 36, 40, 40));
3490*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPath_Close(green_path));
3491*3ac0a46fSAndroid Build Coastguard Worker     FPDFPage_InsertObject(page, green_path);
3492*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderLoadedPage(page);
3493*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792, checksum);
3494*3ac0a46fSAndroid Build Coastguard Worker 
3495*3ac0a46fSAndroid Build Coastguard Worker     // Now save the result, closing the page and document
3496*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPage_GenerateContent(page));
3497*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3498*3ac0a46fSAndroid Build Coastguard Worker     UnloadPage(page);
3499*3ac0a46fSAndroid Build Coastguard Worker   }
3500*3ac0a46fSAndroid Build Coastguard Worker 
3501*3ac0a46fSAndroid Build Coastguard Worker   VerifySavedDocument(612, 792, checksum);
3502*3ac0a46fSAndroid Build Coastguard Worker }
3503*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,AddMark)3504*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, AddMark) {
3505*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text.
3506*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
3507*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
3508*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
3509*3ac0a46fSAndroid Build Coastguard Worker 
3510*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
3511*3ac0a46fSAndroid Build Coastguard Worker 
3512*3ac0a46fSAndroid Build Coastguard Worker   // Add to the first page object a "Bounds" mark with "Position": "First".
3513*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
3514*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(page_object, "Bounds");
3515*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(mark);
3516*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
3517*3ac0a46fSAndroid Build Coastguard Worker                                              "Position", "First"));
3518*3ac0a46fSAndroid Build Coastguard Worker 
3519*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(page, 1, 19, 8, 4, 9, 2);
3520*3ac0a46fSAndroid Build Coastguard Worker 
3521*3ac0a46fSAndroid Build Coastguard Worker   // Save the file
3522*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
3523*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3524*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
3525*3ac0a46fSAndroid Build Coastguard Worker 
3526*3ac0a46fSAndroid Build Coastguard Worker   // Re-open the file and check the new mark is present.
3527*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
3528*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
3529*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
3530*3ac0a46fSAndroid Build Coastguard Worker 
3531*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(saved_page, 1, 19, 8, 4, 9, 2);
3532*3ac0a46fSAndroid Build Coastguard Worker 
3533*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
3534*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
3535*3ac0a46fSAndroid Build Coastguard Worker }
3536*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,AddMarkCompressedStream)3537*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, AddMarkCompressedStream) {
3538*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text in a compressed stream.
3539*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("hello_world_compressed_stream.pdf"));
3540*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
3541*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
3542*3ac0a46fSAndroid Build Coastguard Worker 
3543*3ac0a46fSAndroid Build Coastguard Worker   // Render and check there are no marks.
3544*3ac0a46fSAndroid Build Coastguard Worker   {
3545*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
3546*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, HelloWorldChecksum());
3547*3ac0a46fSAndroid Build Coastguard Worker   }
3548*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(page, 0, 2, 0, 0, 0, 0);
3549*3ac0a46fSAndroid Build Coastguard Worker 
3550*3ac0a46fSAndroid Build Coastguard Worker   // Add to the first page object a "Bounds" mark with "Position": "First".
3551*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
3552*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(page_object, "Bounds");
3553*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(mark);
3554*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
3555*3ac0a46fSAndroid Build Coastguard Worker                                              "Position", "First"));
3556*3ac0a46fSAndroid Build Coastguard Worker 
3557*3ac0a46fSAndroid Build Coastguard Worker   // Render and check there is 1 mark.
3558*3ac0a46fSAndroid Build Coastguard Worker   {
3559*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
3560*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, HelloWorldChecksum());
3561*3ac0a46fSAndroid Build Coastguard Worker   }
3562*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(page, 0, 2, 0, 0, 0, 1);
3563*3ac0a46fSAndroid Build Coastguard Worker 
3564*3ac0a46fSAndroid Build Coastguard Worker   // Save the file.
3565*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
3566*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3567*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
3568*3ac0a46fSAndroid Build Coastguard Worker 
3569*3ac0a46fSAndroid Build Coastguard Worker   // Re-open the file and check the new mark is present.
3570*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
3571*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
3572*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
3573*3ac0a46fSAndroid Build Coastguard Worker 
3574*3ac0a46fSAndroid Build Coastguard Worker   {
3575*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
3576*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 200, 200, HelloWorldChecksum());
3577*3ac0a46fSAndroid Build Coastguard Worker   }
3578*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(saved_page, 0, 2, 0, 0, 0, 1);
3579*3ac0a46fSAndroid Build Coastguard Worker 
3580*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
3581*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
3582*3ac0a46fSAndroid Build Coastguard Worker }
3583*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,SetMarkParam)3584*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, SetMarkParam) {
3585*3ac0a46fSAndroid Build Coastguard Worker   // Load document with some text.
3586*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
3587*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
3588*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
3589*3ac0a46fSAndroid Build Coastguard Worker 
3590*3ac0a46fSAndroid Build Coastguard Worker   constexpr int kExpectedObjectCount = 19;
3591*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
3592*3ac0a46fSAndroid Build Coastguard Worker 
3593*3ac0a46fSAndroid Build Coastguard Worker   // Check the "Bounds" mark's "Position" param is "Last".
3594*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3595*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3596*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(mark);
3597*3ac0a46fSAndroid Build Coastguard Worker   char buffer[256];
3598*3ac0a46fSAndroid Build Coastguard Worker   unsigned long name_len = 999u;
3599*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
3600*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ((6u + 1u) * 2u, name_len);
3601*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(L"Bounds",
3602*3ac0a46fSAndroid Build Coastguard Worker             GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3603*3ac0a46fSAndroid Build Coastguard Worker   unsigned long out_buffer_len;
3604*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFPageObjMark_GetParamStringValue(
3605*3ac0a46fSAndroid Build Coastguard Worker       mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
3606*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(L"Last",
3607*3ac0a46fSAndroid Build Coastguard Worker             GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3608*3ac0a46fSAndroid Build Coastguard Worker 
3609*3ac0a46fSAndroid Build Coastguard Worker   // Set is to "End".
3610*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
3611*3ac0a46fSAndroid Build Coastguard Worker                                              "Position", "End"));
3612*3ac0a46fSAndroid Build Coastguard Worker 
3613*3ac0a46fSAndroid Build Coastguard Worker   // Verify the object passed must correspond to the mark passed.
3614*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT another_page_object = FPDFPage_GetObject(page, 17);
3615*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPageObjMark_SetStringParam(document(), another_page_object,
3616*3ac0a46fSAndroid Build Coastguard Worker                                               mark, "Position", "End"));
3617*3ac0a46fSAndroid Build Coastguard Worker 
3618*3ac0a46fSAndroid Build Coastguard Worker   // Verify nothing else changed.
3619*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
3620*3ac0a46fSAndroid Build Coastguard Worker 
3621*3ac0a46fSAndroid Build Coastguard Worker   // Verify "Position" now maps to "End".
3622*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
3623*3ac0a46fSAndroid Build Coastguard Worker       mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
3624*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(L"End",
3625*3ac0a46fSAndroid Build Coastguard Worker             GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3626*3ac0a46fSAndroid Build Coastguard Worker 
3627*3ac0a46fSAndroid Build Coastguard Worker   // Save the file
3628*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
3629*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3630*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
3631*3ac0a46fSAndroid Build Coastguard Worker 
3632*3ac0a46fSAndroid Build Coastguard Worker   // Re-open the file and cerify "Position" still maps to "End".
3633*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
3634*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
3635*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
3636*3ac0a46fSAndroid Build Coastguard Worker 
3637*3ac0a46fSAndroid Build Coastguard Worker   CheckMarkCounts(saved_page, 1, kExpectedObjectCount, 8, 4, 9, 1);
3638*3ac0a46fSAndroid Build Coastguard Worker   page_object = FPDFPage_GetObject(saved_page, 18);
3639*3ac0a46fSAndroid Build Coastguard Worker   mark = FPDFPageObj_GetMark(page_object, 1);
3640*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
3641*3ac0a46fSAndroid Build Coastguard Worker       mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
3642*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(L"End",
3643*3ac0a46fSAndroid Build Coastguard Worker             GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3644*3ac0a46fSAndroid Build Coastguard Worker 
3645*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
3646*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
3647*3ac0a46fSAndroid Build Coastguard Worker }
3648*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,AddMarkedText)3649*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, AddMarkedText) {
3650*3ac0a46fSAndroid Build Coastguard Worker   // Start with a blank page.
3651*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
3652*3ac0a46fSAndroid Build Coastguard Worker 
3653*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CPDF_Font> stock_font =
3654*3ac0a46fSAndroid Build Coastguard Worker       CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
3655*3ac0a46fSAndroid Build Coastguard Worker   pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
3656*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3657*3ac0a46fSAndroid Build Coastguard Worker                                         FPDF_FONT_TRUETYPE, 0));
3658*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(font.get());
3659*3ac0a46fSAndroid Build Coastguard Worker 
3660*3ac0a46fSAndroid Build Coastguard Worker   // Add some text to the page.
3661*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT text_object =
3662*3ac0a46fSAndroid Build Coastguard Worker       FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
3663*3ac0a46fSAndroid Build Coastguard Worker 
3664*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(text_object);
3665*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFWideString text1 = GetFPDFWideString(kLoadedFontText);
3666*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFText_SetText(text_object, text1.get()));
3667*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
3668*3ac0a46fSAndroid Build Coastguard Worker   FPDFPage_InsertObject(page, text_object);
3669*3ac0a46fSAndroid Build Coastguard Worker 
3670*3ac0a46fSAndroid Build Coastguard Worker   // Add a mark with the tag "TestMarkName" to that text.
3671*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(0, FPDFPageObj_CountMarks(text_object));
3672*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(text_object, "Test Mark Name");
3673*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(mark);
3674*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(1, FPDFPageObj_CountMarks(text_object));
3675*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(mark, FPDFPageObj_GetMark(text_object, 0));
3676*3ac0a46fSAndroid Build Coastguard Worker   char buffer[256];
3677*3ac0a46fSAndroid Build Coastguard Worker   unsigned long name_len = 999u;
3678*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
3679*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ((14u + 1u) * 2, name_len);
3680*3ac0a46fSAndroid Build Coastguard Worker   std::wstring name =
3681*3ac0a46fSAndroid Build Coastguard Worker       GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
3682*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(L"Test Mark Name", name);
3683*3ac0a46fSAndroid Build Coastguard Worker 
3684*3ac0a46fSAndroid Build Coastguard Worker   // Add parameters:
3685*3ac0a46fSAndroid Build Coastguard Worker   // - int "IntKey" : 42
3686*3ac0a46fSAndroid Build Coastguard Worker   // - string "StringKey": "StringValue"
3687*3ac0a46fSAndroid Build Coastguard Worker   // - blob "BlobKey": "\x01\x02\x03\0BlobValue1\0\0\0BlobValue2\0"
3688*3ac0a46fSAndroid Build Coastguard Worker   constexpr size_t kBlobLen = 28;
3689*3ac0a46fSAndroid Build Coastguard Worker   char block_value[kBlobLen];
3690*3ac0a46fSAndroid Build Coastguard Worker   memcpy(block_value, "\x01\x02\x03\0BlobValue1\0\0\0BlobValue2\0", kBlobLen);
3691*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(0, FPDFPageObjMark_CountParams(mark));
3692*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(
3693*3ac0a46fSAndroid Build Coastguard Worker       FPDFPageObjMark_SetIntParam(document(), text_object, mark, "IntKey", 42));
3694*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), text_object, mark,
3695*3ac0a46fSAndroid Build Coastguard Worker                                              "StringKey", "StringValue"));
3696*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObjMark_SetBlobParam(document(), text_object, mark,
3697*3ac0a46fSAndroid Build Coastguard Worker                                            "BlobKey", block_value, kBlobLen));
3698*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(3, FPDFPageObjMark_CountParams(mark));
3699*3ac0a46fSAndroid Build Coastguard Worker 
3700*3ac0a46fSAndroid Build Coastguard Worker   // Check the two parameters can be retrieved.
3701*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_OBJECT_NUMBER,
3702*3ac0a46fSAndroid Build Coastguard Worker             FPDFPageObjMark_GetParamValueType(mark, "IntKey"));
3703*3ac0a46fSAndroid Build Coastguard Worker   int int_value;
3704*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObjMark_GetParamIntValue(mark, "IntKey", &int_value));
3705*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(42, int_value);
3706*3ac0a46fSAndroid Build Coastguard Worker 
3707*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_OBJECT_STRING,
3708*3ac0a46fSAndroid Build Coastguard Worker             FPDFPageObjMark_GetParamValueType(mark, "StringKey"));
3709*3ac0a46fSAndroid Build Coastguard Worker   unsigned long out_buffer_len = 999u;
3710*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
3711*3ac0a46fSAndroid Build Coastguard Worker       mark, "StringKey", buffer, sizeof(buffer), &out_buffer_len));
3712*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_GT(out_buffer_len, 0u);
3713*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_NE(999u, out_buffer_len);
3714*3ac0a46fSAndroid Build Coastguard Worker   name = GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
3715*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(L"StringValue", name);
3716*3ac0a46fSAndroid Build Coastguard Worker 
3717*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_OBJECT_STRING,
3718*3ac0a46fSAndroid Build Coastguard Worker             FPDFPageObjMark_GetParamValueType(mark, "BlobKey"));
3719*3ac0a46fSAndroid Build Coastguard Worker   out_buffer_len = 0;
3720*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObjMark_GetParamBlobValue(
3721*3ac0a46fSAndroid Build Coastguard Worker       mark, "BlobKey", buffer, sizeof(buffer), &out_buffer_len));
3722*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(kBlobLen, out_buffer_len);
3723*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(0, memcmp(block_value, buffer, kBlobLen));
3724*3ac0a46fSAndroid Build Coastguard Worker 
3725*3ac0a46fSAndroid Build Coastguard Worker   // Render and check the bitmap is the expected one.
3726*3ac0a46fSAndroid Build Coastguard Worker   {
3727*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap page_bitmap = RenderPage(page);
3728*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(page_bitmap.get(), 612, 792, LoadedFontTextChecksum());
3729*3ac0a46fSAndroid Build Coastguard Worker   }
3730*3ac0a46fSAndroid Build Coastguard Worker 
3731*3ac0a46fSAndroid Build Coastguard Worker   // Now save the result.
3732*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(1, FPDFPage_CountObjects(page));
3733*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPage_GenerateContent(page));
3734*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3735*3ac0a46fSAndroid Build Coastguard Worker 
3736*3ac0a46fSAndroid Build Coastguard Worker   FPDF_ClosePage(page);
3737*3ac0a46fSAndroid Build Coastguard Worker 
3738*3ac0a46fSAndroid Build Coastguard Worker   // Re-open the file and check the changes were kept in the saved .pdf.
3739*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenSavedDocument());
3740*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE saved_page = LoadSavedPage(0);
3741*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(saved_page);
3742*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(1, FPDFPage_CountObjects(saved_page));
3743*3ac0a46fSAndroid Build Coastguard Worker 
3744*3ac0a46fSAndroid Build Coastguard Worker   text_object = FPDFPage_GetObject(saved_page, 0);
3745*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(text_object);
3746*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(1, FPDFPageObj_CountMarks(text_object));
3747*3ac0a46fSAndroid Build Coastguard Worker   mark = FPDFPageObj_GetMark(text_object, 0);
3748*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(mark);
3749*3ac0a46fSAndroid Build Coastguard Worker 
3750*3ac0a46fSAndroid Build Coastguard Worker   name_len = 999u;
3751*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
3752*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ((14u + 1u) * 2, name_len);
3753*3ac0a46fSAndroid Build Coastguard Worker   name = GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
3754*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(L"Test Mark Name", name);
3755*3ac0a46fSAndroid Build Coastguard Worker 
3756*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedPage(saved_page);
3757*3ac0a46fSAndroid Build Coastguard Worker   CloseSavedDocument();
3758*3ac0a46fSAndroid Build Coastguard Worker }
3759*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,MarkGetName)3760*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, MarkGetName) {
3761*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
3762*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
3763*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
3764*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3765*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3766*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(mark);
3767*3ac0a46fSAndroid Build Coastguard Worker 
3768*3ac0a46fSAndroid Build Coastguard Worker   char buffer[256];
3769*3ac0a46fSAndroid Build Coastguard Worker   unsigned long out_len;
3770*3ac0a46fSAndroid Build Coastguard Worker 
3771*3ac0a46fSAndroid Build Coastguard Worker   // Show the positive cases of FPDFPageObjMark_GetName.
3772*3ac0a46fSAndroid Build Coastguard Worker   out_len = 999u;
3773*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObjMark_GetName(mark, nullptr, 0, &out_len));
3774*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ((6u + 1u) * 2u, out_len);
3775*3ac0a46fSAndroid Build Coastguard Worker 
3776*3ac0a46fSAndroid Build Coastguard Worker   out_len = 999u;
3777*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &out_len));
3778*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(L"Bounds",
3779*3ac0a46fSAndroid Build Coastguard Worker             GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3780*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ((6u + 1u) * 2u, out_len);
3781*3ac0a46fSAndroid Build Coastguard Worker 
3782*3ac0a46fSAndroid Build Coastguard Worker   // Show the negative cases of FPDFPageObjMark_GetName.
3783*3ac0a46fSAndroid Build Coastguard Worker   out_len = 999u;
3784*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(
3785*3ac0a46fSAndroid Build Coastguard Worker       FPDFPageObjMark_GetName(nullptr, buffer, sizeof(buffer), &out_len));
3786*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(999u, out_len);
3787*3ac0a46fSAndroid Build Coastguard Worker 
3788*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), nullptr));
3789*3ac0a46fSAndroid Build Coastguard Worker 
3790*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
3791*3ac0a46fSAndroid Build Coastguard Worker }
3792*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,MarkGetParamKey)3793*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, MarkGetParamKey) {
3794*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
3795*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
3796*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
3797*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3798*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3799*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(mark);
3800*3ac0a46fSAndroid Build Coastguard Worker 
3801*3ac0a46fSAndroid Build Coastguard Worker   char buffer[256];
3802*3ac0a46fSAndroid Build Coastguard Worker   unsigned long out_len;
3803*3ac0a46fSAndroid Build Coastguard Worker 
3804*3ac0a46fSAndroid Build Coastguard Worker   // Show the positive cases of FPDFPageObjMark_GetParamKey.
3805*3ac0a46fSAndroid Build Coastguard Worker   out_len = 999u;
3806*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObjMark_GetParamKey(mark, 0, nullptr, 0, &out_len));
3807*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ((8u + 1u) * 2u, out_len);
3808*3ac0a46fSAndroid Build Coastguard Worker 
3809*3ac0a46fSAndroid Build Coastguard Worker   out_len = 999u;
3810*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(
3811*3ac0a46fSAndroid Build Coastguard Worker       FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer), &out_len));
3812*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(L"Position",
3813*3ac0a46fSAndroid Build Coastguard Worker             GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3814*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ((8u + 1u) * 2u, out_len);
3815*3ac0a46fSAndroid Build Coastguard Worker 
3816*3ac0a46fSAndroid Build Coastguard Worker   // Show the negative cases of FPDFPageObjMark_GetParamKey.
3817*3ac0a46fSAndroid Build Coastguard Worker   out_len = 999u;
3818*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPageObjMark_GetParamKey(nullptr, 0, buffer, sizeof(buffer),
3819*3ac0a46fSAndroid Build Coastguard Worker                                            &out_len));
3820*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(999u, out_len);
3821*3ac0a46fSAndroid Build Coastguard Worker 
3822*3ac0a46fSAndroid Build Coastguard Worker   out_len = 999u;
3823*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(
3824*3ac0a46fSAndroid Build Coastguard Worker       FPDFPageObjMark_GetParamKey(mark, 1, buffer, sizeof(buffer), &out_len));
3825*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(999u, out_len);
3826*3ac0a46fSAndroid Build Coastguard Worker 
3827*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(
3828*3ac0a46fSAndroid Build Coastguard Worker       FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer), nullptr));
3829*3ac0a46fSAndroid Build Coastguard Worker 
3830*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
3831*3ac0a46fSAndroid Build Coastguard Worker }
3832*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,MarkGetIntParam)3833*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, MarkGetIntParam) {
3834*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
3835*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
3836*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
3837*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 8);
3838*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 0);
3839*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(mark);
3840*3ac0a46fSAndroid Build Coastguard Worker 
3841*3ac0a46fSAndroid Build Coastguard Worker   int out_value;
3842*3ac0a46fSAndroid Build Coastguard Worker 
3843*3ac0a46fSAndroid Build Coastguard Worker   // Show the positive cases of FPDFPageObjMark_GetParamIntValue.
3844*3ac0a46fSAndroid Build Coastguard Worker   out_value = 999;
3845*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
3846*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(3, out_value);
3847*3ac0a46fSAndroid Build Coastguard Worker 
3848*3ac0a46fSAndroid Build Coastguard Worker   // Show the negative cases of FPDFPageObjMark_GetParamIntValue.
3849*3ac0a46fSAndroid Build Coastguard Worker   out_value = 999;
3850*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(nullptr, "Factor", &out_value));
3851*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(999, out_value);
3852*3ac0a46fSAndroid Build Coastguard Worker 
3853*3ac0a46fSAndroid Build Coastguard Worker   out_value = 999;
3854*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "ParamThatDoesNotExist",
3855*3ac0a46fSAndroid Build Coastguard Worker                                                 &out_value));
3856*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(999, out_value);
3857*3ac0a46fSAndroid Build Coastguard Worker 
3858*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "Factor", nullptr));
3859*3ac0a46fSAndroid Build Coastguard Worker 
3860*3ac0a46fSAndroid Build Coastguard Worker   page_object = FPDFPage_GetObject(page, 18);
3861*3ac0a46fSAndroid Build Coastguard Worker   mark = FPDFPageObj_GetMark(page_object, 1);
3862*3ac0a46fSAndroid Build Coastguard Worker   out_value = 999;
3863*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "Position", &out_value));
3864*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(999, out_value);
3865*3ac0a46fSAndroid Build Coastguard Worker 
3866*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
3867*3ac0a46fSAndroid Build Coastguard Worker }
3868*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,MarkGetStringParam)3869*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, MarkGetStringParam) {
3870*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
3871*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
3872*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
3873*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3874*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3875*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(mark);
3876*3ac0a46fSAndroid Build Coastguard Worker 
3877*3ac0a46fSAndroid Build Coastguard Worker   char buffer[256];
3878*3ac0a46fSAndroid Build Coastguard Worker   unsigned long out_len;
3879*3ac0a46fSAndroid Build Coastguard Worker 
3880*3ac0a46fSAndroid Build Coastguard Worker   // Show the positive cases of FPDFPageObjMark_GetParamStringValue.
3881*3ac0a46fSAndroid Build Coastguard Worker   out_len = 999u;
3882*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(mark, "Position", nullptr, 0,
3883*3ac0a46fSAndroid Build Coastguard Worker                                                   &out_len));
3884*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ((4u + 1u) * 2u, out_len);
3885*3ac0a46fSAndroid Build Coastguard Worker 
3886*3ac0a46fSAndroid Build Coastguard Worker   out_len = 999u;
3887*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(mark, "Position", buffer,
3888*3ac0a46fSAndroid Build Coastguard Worker                                                   sizeof(buffer), &out_len));
3889*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(L"Last",
3890*3ac0a46fSAndroid Build Coastguard Worker             GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3891*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ((4u + 1u) * 2u, out_len);
3892*3ac0a46fSAndroid Build Coastguard Worker 
3893*3ac0a46fSAndroid Build Coastguard Worker   // Show the negative cases of FPDFPageObjMark_GetParamStringValue.
3894*3ac0a46fSAndroid Build Coastguard Worker   out_len = 999u;
3895*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(nullptr, "Position", buffer,
3896*3ac0a46fSAndroid Build Coastguard Worker                                                    sizeof(buffer), &out_len));
3897*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(999u, out_len);
3898*3ac0a46fSAndroid Build Coastguard Worker 
3899*3ac0a46fSAndroid Build Coastguard Worker   out_len = 999u;
3900*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(
3901*3ac0a46fSAndroid Build Coastguard Worker       mark, "ParamThatDoesNotExist", buffer, sizeof(buffer), &out_len));
3902*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(999u, out_len);
3903*3ac0a46fSAndroid Build Coastguard Worker 
3904*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(mark, "Position", buffer,
3905*3ac0a46fSAndroid Build Coastguard Worker                                                    sizeof(buffer), nullptr));
3906*3ac0a46fSAndroid Build Coastguard Worker 
3907*3ac0a46fSAndroid Build Coastguard Worker   page_object = FPDFPage_GetObject(page, 8);
3908*3ac0a46fSAndroid Build Coastguard Worker   mark = FPDFPageObj_GetMark(page_object, 0);
3909*3ac0a46fSAndroid Build Coastguard Worker   out_len = 999u;
3910*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(mark, "Factor", buffer,
3911*3ac0a46fSAndroid Build Coastguard Worker                                                    sizeof(buffer), &out_len));
3912*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(999u, out_len);
3913*3ac0a46fSAndroid Build Coastguard Worker 
3914*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
3915*3ac0a46fSAndroid Build Coastguard Worker }
3916*3ac0a46fSAndroid Build Coastguard Worker 
3917*3ac0a46fSAndroid Build Coastguard Worker // See also FPDFStructTreeEmbedderTest.GetMarkedContentID, which traverses the
3918*3ac0a46fSAndroid Build Coastguard Worker // marked contents using FPDF_StructTree_GetForPage() and related API.
TEST_F(FPDFEditEmbedderTest,TraverseMarkedContentID)3919*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, TraverseMarkedContentID) {
3920*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("marked_content_id.pdf"));
3921*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
3922*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
3923*3ac0a46fSAndroid Build Coastguard Worker 
3924*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPage_CountObjects(page));
3925*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT object1 = FPDFPage_GetObject(page, 0);
3926*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(object1);
3927*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFPageObj_CountMarks(object1));
3928*3ac0a46fSAndroid Build Coastguard Worker 
3929*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECTMARK mark11 = FPDFPageObj_GetMark(object1, 0);
3930*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(mark11);
3931*3ac0a46fSAndroid Build Coastguard Worker   unsigned long len = 0;
3932*3ac0a46fSAndroid Build Coastguard Worker   unsigned short buf[40];
3933*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFPageObjMark_GetName(mark11, buf, sizeof(buf), &len));
3934*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(18u, len);
3935*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(L"Artifact", GetPlatformWString(buf));
3936*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPageObjMark_CountParams(mark11));
3937*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark11, 0, buf, sizeof(buf), &len));
3938*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(10u, len);
3939*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(L"BBox", GetPlatformWString(buf));
3940*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_OBJECT_ARRAY,
3941*3ac0a46fSAndroid Build Coastguard Worker             FPDFPageObjMark_GetParamValueType(mark11, "BBox"));
3942*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark11, 1, buf, sizeof(buf), &len));
3943*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(10u, len);
3944*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(L"Type", GetPlatformWString(buf));
3945*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_OBJECT_NAME,
3946*3ac0a46fSAndroid Build Coastguard Worker             FPDFPageObjMark_GetParamValueType(mark11, "Type"));
3947*3ac0a46fSAndroid Build Coastguard Worker 
3948*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT object2 = FPDFPage_GetObject(page, 1);
3949*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(object2);
3950*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFPageObj_CountMarks(object2));
3951*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(object2));
3952*3ac0a46fSAndroid Build Coastguard Worker 
3953*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECTMARK mark21 = FPDFPageObj_GetMark(object2, 0);
3954*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(mark21);
3955*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFPageObjMark_GetName(mark21, buf, sizeof(buf), &len));
3956*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(14u, len);
3957*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(L"Figure", GetPlatformWString(buf));
3958*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFPageObjMark_CountParams(mark21));
3959*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark21, 0, buf, sizeof(buf), &len));
3960*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(10u, len);
3961*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(L"MCID", GetPlatformWString(buf));
3962*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_OBJECT_NUMBER,
3963*3ac0a46fSAndroid Build Coastguard Worker             FPDFPageObjMark_GetParamValueType(mark21, "MCID"));
3964*3ac0a46fSAndroid Build Coastguard Worker   int mcid = -1;
3965*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFPageObjMark_GetParamIntValue(mark21, "MCID", &mcid));
3966*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(0, mcid);
3967*3ac0a46fSAndroid Build Coastguard Worker 
3968*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECTMARK mark22 = FPDFPageObj_GetMark(object2, 1);
3969*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(mark22);
3970*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFPageObjMark_GetName(mark22, buf, sizeof(buf), &len));
3971*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(18u, len);
3972*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(L"ClipSpan", GetPlatformWString(buf));
3973*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(0, FPDFPageObjMark_CountParams(mark22));
3974*3ac0a46fSAndroid Build Coastguard Worker 
3975*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
3976*3ac0a46fSAndroid Build Coastguard Worker }
3977*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GetBitmap)3978*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GetBitmap) {
3979*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3980*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
3981*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
3982*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(39, FPDFPage_CountObjects(page));
3983*3ac0a46fSAndroid Build Coastguard Worker 
3984*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 32);
3985*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_NE(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3986*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFImageObj_GetBitmap(obj));
3987*3ac0a46fSAndroid Build Coastguard Worker 
3988*3ac0a46fSAndroid Build Coastguard Worker   {
3989*3ac0a46fSAndroid Build Coastguard Worker     obj = FPDFPage_GetObject(page, 33);
3990*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3991*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3992*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3993*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(bitmap.get(), 109, 88, kEmbeddedImage33Checksum);
3994*3ac0a46fSAndroid Build Coastguard Worker   }
3995*3ac0a46fSAndroid Build Coastguard Worker 
3996*3ac0a46fSAndroid Build Coastguard Worker   {
3997*3ac0a46fSAndroid Build Coastguard Worker     obj = FPDFPage_GetObject(page, 34);
3998*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3999*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
4000*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
4001*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(bitmap.get(), 103, 75, "c8d51fa6821ceb2a67f08446ff236c40");
4002*3ac0a46fSAndroid Build Coastguard Worker   }
4003*3ac0a46fSAndroid Build Coastguard Worker 
4004*3ac0a46fSAndroid Build Coastguard Worker   {
4005*3ac0a46fSAndroid Build Coastguard Worker     obj = FPDFPage_GetObject(page, 35);
4006*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4007*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
4008*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(FPDFBitmap_Gray, FPDFBitmap_GetFormat(bitmap.get()));
4009*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(bitmap.get(), 92, 68, "9c6d76cb1e37ef8514f9455d759391f3");
4010*3ac0a46fSAndroid Build Coastguard Worker   }
4011*3ac0a46fSAndroid Build Coastguard Worker 
4012*3ac0a46fSAndroid Build Coastguard Worker   {
4013*3ac0a46fSAndroid Build Coastguard Worker     obj = FPDFPage_GetObject(page, 36);
4014*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4015*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
4016*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
4017*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(bitmap.get(), 79, 60, "f4e72fb783a01c7b4614cdc25eaa98ac");
4018*3ac0a46fSAndroid Build Coastguard Worker   }
4019*3ac0a46fSAndroid Build Coastguard Worker 
4020*3ac0a46fSAndroid Build Coastguard Worker   {
4021*3ac0a46fSAndroid Build Coastguard Worker     obj = FPDFPage_GetObject(page, 37);
4022*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4023*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
4024*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
4025*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(bitmap.get(), 126, 106, "2cf9e66414c72461f4ccbf9cdebdfa1b");
4026*3ac0a46fSAndroid Build Coastguard Worker   }
4027*3ac0a46fSAndroid Build Coastguard Worker 
4028*3ac0a46fSAndroid Build Coastguard Worker   {
4029*3ac0a46fSAndroid Build Coastguard Worker     obj = FPDFPage_GetObject(page, 38);
4030*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4031*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
4032*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
4033*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(bitmap.get(), 194, 119, "a8f3a126cec274dab8242fd2ccdc1b8b");
4034*3ac0a46fSAndroid Build Coastguard Worker   }
4035*3ac0a46fSAndroid Build Coastguard Worker 
4036*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
4037*3ac0a46fSAndroid Build Coastguard Worker }
4038*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GetBitmapIgnoresSetMatrix)4039*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GetBitmapIgnoresSetMatrix) {
4040*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4041*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
4042*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
4043*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(39, FPDFPage_CountObjects(page));
4044*3ac0a46fSAndroid Build Coastguard Worker 
4045*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
4046*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4047*3ac0a46fSAndroid Build Coastguard Worker 
4048*3ac0a46fSAndroid Build Coastguard Worker   {
4049*3ac0a46fSAndroid Build Coastguard Worker     // Render |obj| as is.
4050*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
4051*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
4052*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(bitmap.get(), 109, 88, kEmbeddedImage33Checksum);
4053*3ac0a46fSAndroid Build Coastguard Worker   }
4054*3ac0a46fSAndroid Build Coastguard Worker 
4055*3ac0a46fSAndroid Build Coastguard Worker   // Check the matrix for |obj|.
4056*3ac0a46fSAndroid Build Coastguard Worker   FS_MATRIX matrix;
4057*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4058*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(53.0f, matrix.a);
4059*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.0f, matrix.b);
4060*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.0f, matrix.c);
4061*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(43.0f, matrix.d);
4062*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(72.0f, matrix.e);
4063*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
4064*3ac0a46fSAndroid Build Coastguard Worker 
4065*3ac0a46fSAndroid Build Coastguard Worker   // Modify the matrix for |obj|.
4066*3ac0a46fSAndroid Build Coastguard Worker   matrix.a = 120.0;
4067*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetMatrix(obj, &matrix));
4068*3ac0a46fSAndroid Build Coastguard Worker 
4069*3ac0a46fSAndroid Build Coastguard Worker   // Make sure the matrix modification took place.
4070*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4071*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(120.0f, matrix.a);
4072*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.0f, matrix.b);
4073*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.0f, matrix.c);
4074*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(43.0f, matrix.d);
4075*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(72.0f, matrix.e);
4076*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
4077*3ac0a46fSAndroid Build Coastguard Worker 
4078*3ac0a46fSAndroid Build Coastguard Worker   {
4079*3ac0a46fSAndroid Build Coastguard Worker     // Render |obj| again. Note that the FPDFPageObj_SetMatrix() call has no
4080*3ac0a46fSAndroid Build Coastguard Worker     // effect.
4081*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
4082*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
4083*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(bitmap.get(), 109, 88, kEmbeddedImage33Checksum);
4084*3ac0a46fSAndroid Build Coastguard Worker   }
4085*3ac0a46fSAndroid Build Coastguard Worker 
4086*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
4087*3ac0a46fSAndroid Build Coastguard Worker }
4088*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GetBitmapForJBigImage)4089*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GetBitmapForJBigImage) {
4090*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("bug_631912.pdf"));
4091*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
4092*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
4093*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFPage_CountObjects(page));
4094*3ac0a46fSAndroid Build Coastguard Worker 
4095*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 0);
4096*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4097*3ac0a46fSAndroid Build Coastguard Worker   {
4098*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
4099*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(bitmap);
4100*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(FPDFBitmap_Gray, FPDFBitmap_GetFormat(bitmap.get()));
4101*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(bitmap.get(), 1152, 720, "3f6a48e2b3e91b799bf34567f55cb4de");
4102*3ac0a46fSAndroid Build Coastguard Worker   }
4103*3ac0a46fSAndroid Build Coastguard Worker 
4104*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
4105*3ac0a46fSAndroid Build Coastguard Worker }
4106*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GetBitmapIgnoresSMask)4107*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GetBitmapIgnoresSMask) {
4108*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("matte.pdf"));
4109*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
4110*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
4111*3ac0a46fSAndroid Build Coastguard Worker 
4112*3ac0a46fSAndroid Build Coastguard Worker   constexpr int kExpectedObjects = 4;
4113*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(kExpectedObjects, FPDFPage_CountObjects(page));
4114*3ac0a46fSAndroid Build Coastguard Worker 
4115*3ac0a46fSAndroid Build Coastguard Worker   for (int i = 0; i < kExpectedObjects; ++i) {
4116*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, i);
4117*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4118*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
4119*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(bitmap);
4120*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
4121*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(bitmap.get(), 50, 50, "46c9a1dbe0b44765ce46017ad629a2fe");
4122*3ac0a46fSAndroid Build Coastguard Worker   }
4123*3ac0a46fSAndroid Build Coastguard Worker 
4124*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
4125*3ac0a46fSAndroid Build Coastguard Worker }
4126*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GetRenderedBitmapHandlesSetMatrix)4127*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GetRenderedBitmapHandlesSetMatrix) {
4128*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4129*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
4130*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
4131*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(39, FPDFPage_CountObjects(page));
4132*3ac0a46fSAndroid Build Coastguard Worker 
4133*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
4134*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4135*3ac0a46fSAndroid Build Coastguard Worker 
4136*3ac0a46fSAndroid Build Coastguard Worker   {
4137*3ac0a46fSAndroid Build Coastguard Worker     // Render `obj` as is.
4138*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap(
4139*3ac0a46fSAndroid Build Coastguard Worker         FPDFImageObj_GetRenderedBitmap(document(), page, obj));
4140*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(FPDFBitmap_BGRA, FPDFBitmap_GetFormat(bitmap.get()));
4141*3ac0a46fSAndroid Build Coastguard Worker     const char* checksum = []() {
4142*3ac0a46fSAndroid Build Coastguard Worker       if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
4143*3ac0a46fSAndroid Build Coastguard Worker         return "3b51fc066ee18efbf70bab0501763603";
4144*3ac0a46fSAndroid Build Coastguard Worker       return "582ca300e003f512d7b552c7b5b45d2e";
4145*3ac0a46fSAndroid Build Coastguard Worker     }();
4146*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(bitmap.get(), 53, 43, checksum);
4147*3ac0a46fSAndroid Build Coastguard Worker   }
4148*3ac0a46fSAndroid Build Coastguard Worker 
4149*3ac0a46fSAndroid Build Coastguard Worker   // Check the matrix for `obj`.
4150*3ac0a46fSAndroid Build Coastguard Worker   FS_MATRIX matrix;
4151*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4152*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(53.0f, matrix.a);
4153*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.0f, matrix.b);
4154*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.0f, matrix.c);
4155*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(43.0f, matrix.d);
4156*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(72.0f, matrix.e);
4157*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
4158*3ac0a46fSAndroid Build Coastguard Worker 
4159*3ac0a46fSAndroid Build Coastguard Worker   // Modify the matrix for `obj`.
4160*3ac0a46fSAndroid Build Coastguard Worker   matrix.a = 120.0;
4161*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_SetMatrix(obj, &matrix));
4162*3ac0a46fSAndroid Build Coastguard Worker 
4163*3ac0a46fSAndroid Build Coastguard Worker   // Make sure the matrix modification took place.
4164*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4165*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(120.0f, matrix.a);
4166*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.0f, matrix.b);
4167*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.0f, matrix.c);
4168*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(43.0f, matrix.d);
4169*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(72.0f, matrix.e);
4170*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
4171*3ac0a46fSAndroid Build Coastguard Worker 
4172*3ac0a46fSAndroid Build Coastguard Worker   {
4173*3ac0a46fSAndroid Build Coastguard Worker     // Render `obj` again. Note that the FPDFPageObj_SetMatrix() call has an
4174*3ac0a46fSAndroid Build Coastguard Worker     // effect.
4175*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap(
4176*3ac0a46fSAndroid Build Coastguard Worker         FPDFImageObj_GetRenderedBitmap(document(), page, obj));
4177*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(FPDFBitmap_BGRA, FPDFBitmap_GetFormat(bitmap.get()));
4178*3ac0a46fSAndroid Build Coastguard Worker     const char* checksum = []() {
4179*3ac0a46fSAndroid Build Coastguard Worker       if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
4180*3ac0a46fSAndroid Build Coastguard Worker         return "1003585870ad0fe37baf1c5bb3f5fd76";
4181*3ac0a46fSAndroid Build Coastguard Worker       return "0824c16dcf2dfcef44b45d88db1fddce";
4182*3ac0a46fSAndroid Build Coastguard Worker     }();
4183*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(bitmap.get(), 120, 43, checksum);
4184*3ac0a46fSAndroid Build Coastguard Worker   }
4185*3ac0a46fSAndroid Build Coastguard Worker 
4186*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
4187*3ac0a46fSAndroid Build Coastguard Worker }
4188*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GetRenderedBitmapHandlesSMask)4189*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GetRenderedBitmapHandlesSMask) {
4190*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("matte.pdf"));
4191*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
4192*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
4193*3ac0a46fSAndroid Build Coastguard Worker 
4194*3ac0a46fSAndroid Build Coastguard Worker   constexpr int kExpectedObjects = 4;
4195*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(kExpectedObjects, FPDFPage_CountObjects(page));
4196*3ac0a46fSAndroid Build Coastguard Worker 
4197*3ac0a46fSAndroid Build Coastguard Worker   const char* smask_checksum = []() {
4198*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
4199*3ac0a46fSAndroid Build Coastguard Worker       return "0653a18f3bf9b4d8413a2aa10bc11c38";
4200*3ac0a46fSAndroid Build Coastguard Worker     }
4201*3ac0a46fSAndroid Build Coastguard Worker     return "5a3ae4a660ce919e29c42ec2258142f1";
4202*3ac0a46fSAndroid Build Coastguard Worker   }();
4203*3ac0a46fSAndroid Build Coastguard Worker   const char* no_smask_checksum = []() {
4204*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
4205*3ac0a46fSAndroid Build Coastguard Worker       return "0da49e63e7d6337aca78b19938e3bf65";
4206*3ac0a46fSAndroid Build Coastguard Worker     }
4207*3ac0a46fSAndroid Build Coastguard Worker     return "67504e83f5d78214ea00efc19082c5c1";
4208*3ac0a46fSAndroid Build Coastguard Worker   }();
4209*3ac0a46fSAndroid Build Coastguard Worker 
4210*3ac0a46fSAndroid Build Coastguard Worker   for (int i = 0; i < kExpectedObjects; ++i) {
4211*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, i);
4212*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4213*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap(
4214*3ac0a46fSAndroid Build Coastguard Worker         FPDFImageObj_GetRenderedBitmap(document(), page, obj));
4215*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(bitmap);
4216*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_EQ(FPDFBitmap_BGRA, FPDFBitmap_GetFormat(bitmap.get()));
4217*3ac0a46fSAndroid Build Coastguard Worker     if (i == 0)
4218*3ac0a46fSAndroid Build Coastguard Worker       CompareBitmap(bitmap.get(), 40, 60, smask_checksum);
4219*3ac0a46fSAndroid Build Coastguard Worker     else
4220*3ac0a46fSAndroid Build Coastguard Worker       CompareBitmap(bitmap.get(), 40, 60, no_smask_checksum);
4221*3ac0a46fSAndroid Build Coastguard Worker   }
4222*3ac0a46fSAndroid Build Coastguard Worker 
4223*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
4224*3ac0a46fSAndroid Build Coastguard Worker }
4225*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GetRenderedBitmapBadParams)4226*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GetRenderedBitmapBadParams) {
4227*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4228*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
4229*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
4230*3ac0a46fSAndroid Build Coastguard Worker 
4231*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
4232*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4233*3ac0a46fSAndroid Build Coastguard Worker 
4234*3ac0a46fSAndroid Build Coastguard Worker   // Test various null parameters.
4235*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, nullptr, nullptr));
4236*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(document(), nullptr, nullptr));
4237*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, page, nullptr));
4238*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, nullptr, obj));
4239*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(document(), page, nullptr));
4240*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, page, obj));
4241*3ac0a46fSAndroid Build Coastguard Worker 
4242*3ac0a46fSAndroid Build Coastguard Worker   // Test mismatch between document and page parameters.
4243*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFDocument new_document(FPDF_CreateNewDocument());
4244*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(new_document.get(), page, obj));
4245*3ac0a46fSAndroid Build Coastguard Worker 
4246*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
4247*3ac0a46fSAndroid Build Coastguard Worker }
4248*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GetImageData)4249*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GetImageData) {
4250*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4251*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
4252*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
4253*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(39, FPDFPage_CountObjects(page));
4254*3ac0a46fSAndroid Build Coastguard Worker 
4255*3ac0a46fSAndroid Build Coastguard Worker   // Retrieve an image object with flate-encoded data stream.
4256*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
4257*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4258*3ac0a46fSAndroid Build Coastguard Worker 
4259*3ac0a46fSAndroid Build Coastguard Worker   // Check that the raw image data has the correct length and hash value.
4260*3ac0a46fSAndroid Build Coastguard Worker   unsigned long len = FPDFImageObj_GetImageDataRaw(obj, nullptr, 0);
4261*3ac0a46fSAndroid Build Coastguard Worker   std::vector<uint8_t> buf(len);
4262*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(4091u, FPDFImageObj_GetImageDataRaw(obj, buf.data(), len));
4263*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("f73802327d2e88e890f653961bcda81a", GenerateMD5Base16(buf));
4264*3ac0a46fSAndroid Build Coastguard Worker 
4265*3ac0a46fSAndroid Build Coastguard Worker   // Check that the decoded image data has the correct length and hash value.
4266*3ac0a46fSAndroid Build Coastguard Worker   len = FPDFImageObj_GetImageDataDecoded(obj, nullptr, 0);
4267*3ac0a46fSAndroid Build Coastguard Worker   buf.clear();
4268*3ac0a46fSAndroid Build Coastguard Worker   buf.resize(len);
4269*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(28776u, FPDFImageObj_GetImageDataDecoded(obj, buf.data(), len));
4270*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(kEmbeddedImage33Checksum, GenerateMD5Base16(buf));
4271*3ac0a46fSAndroid Build Coastguard Worker 
4272*3ac0a46fSAndroid Build Coastguard Worker   // Retrieve an image object with DCTDecode-encoded data stream.
4273*3ac0a46fSAndroid Build Coastguard Worker   obj = FPDFPage_GetObject(page, 37);
4274*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4275*3ac0a46fSAndroid Build Coastguard Worker 
4276*3ac0a46fSAndroid Build Coastguard Worker   // Check that the raw image data has the correct length and hash value.
4277*3ac0a46fSAndroid Build Coastguard Worker   len = FPDFImageObj_GetImageDataRaw(obj, nullptr, 0);
4278*3ac0a46fSAndroid Build Coastguard Worker   buf.clear();
4279*3ac0a46fSAndroid Build Coastguard Worker   buf.resize(len);
4280*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(4370u, FPDFImageObj_GetImageDataRaw(obj, buf.data(), len));
4281*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("6aae1f3710335023a9e12191be66b64b", GenerateMD5Base16(buf));
4282*3ac0a46fSAndroid Build Coastguard Worker 
4283*3ac0a46fSAndroid Build Coastguard Worker   // Check that the decoded image data has the correct length and hash value,
4284*3ac0a46fSAndroid Build Coastguard Worker   // which should be the same as those of the raw data, since this image is
4285*3ac0a46fSAndroid Build Coastguard Worker   // encoded by a single DCTDecode filter and decoding is a noop.
4286*3ac0a46fSAndroid Build Coastguard Worker   len = FPDFImageObj_GetImageDataDecoded(obj, nullptr, 0);
4287*3ac0a46fSAndroid Build Coastguard Worker   buf.clear();
4288*3ac0a46fSAndroid Build Coastguard Worker   buf.resize(len);
4289*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(4370u, FPDFImageObj_GetImageDataDecoded(obj, buf.data(), len));
4290*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ("6aae1f3710335023a9e12191be66b64b", GenerateMD5Base16(buf));
4291*3ac0a46fSAndroid Build Coastguard Worker 
4292*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
4293*3ac0a46fSAndroid Build Coastguard Worker }
4294*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GetImageMatrix)4295*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GetImageMatrix) {
4296*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4297*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
4298*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
4299*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(39, FPDFPage_CountObjects(page));
4300*3ac0a46fSAndroid Build Coastguard Worker 
4301*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT obj;
4302*3ac0a46fSAndroid Build Coastguard Worker   FS_MATRIX matrix;
4303*3ac0a46fSAndroid Build Coastguard Worker 
4304*3ac0a46fSAndroid Build Coastguard Worker   obj = FPDFPage_GetObject(page, 33);
4305*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4306*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4307*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(53.0f, matrix.a);
4308*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.0f, matrix.b);
4309*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.0f, matrix.c);
4310*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(43.0f, matrix.d);
4311*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(72.0f, matrix.e);
4312*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
4313*3ac0a46fSAndroid Build Coastguard Worker 
4314*3ac0a46fSAndroid Build Coastguard Worker   obj = FPDFPage_GetObject(page, 34);
4315*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4316*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4317*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(70.0f, matrix.a);
4318*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.0f, matrix.b);
4319*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.0f, matrix.c);
4320*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(51.0f, matrix.d);
4321*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(216.0f, matrix.e);
4322*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
4323*3ac0a46fSAndroid Build Coastguard Worker 
4324*3ac0a46fSAndroid Build Coastguard Worker   obj = FPDFPage_GetObject(page, 35);
4325*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4326*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4327*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(69.0f, matrix.a);
4328*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.0f, matrix.b);
4329*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.0f, matrix.c);
4330*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(51.0f, matrix.d);
4331*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(360.0f, matrix.e);
4332*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
4333*3ac0a46fSAndroid Build Coastguard Worker 
4334*3ac0a46fSAndroid Build Coastguard Worker   obj = FPDFPage_GetObject(page, 36);
4335*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4336*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4337*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(59.0f, matrix.a);
4338*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.0f, matrix.b);
4339*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.0f, matrix.c);
4340*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(45.0f, matrix.d);
4341*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(72.0f, matrix.e);
4342*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(553.510009765625f, matrix.f);
4343*3ac0a46fSAndroid Build Coastguard Worker 
4344*3ac0a46fSAndroid Build Coastguard Worker   obj = FPDFPage_GetObject(page, 37);
4345*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4346*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4347*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(55.94000244140625f, matrix.a);
4348*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.0f, matrix.b);
4349*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.0f, matrix.c);
4350*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(46.950000762939453f, matrix.d);
4351*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(216.0f, matrix.e);
4352*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(552.510009765625f, matrix.f);
4353*3ac0a46fSAndroid Build Coastguard Worker 
4354*3ac0a46fSAndroid Build Coastguard Worker   obj = FPDFPage_GetObject(page, 38);
4355*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4356*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4357*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(70.528999328613281f, matrix.a);
4358*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.0f, matrix.b);
4359*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(0.0f, matrix.c);
4360*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(43.149997711181641f, matrix.d);
4361*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(360.0f, matrix.e);
4362*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(553.3599853515625f, matrix.f);
4363*3ac0a46fSAndroid Build Coastguard Worker 
4364*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
4365*3ac0a46fSAndroid Build Coastguard Worker }
4366*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,DestroyPageObject)4367*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, DestroyPageObject) {
4368*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
4369*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(rect);
4370*3ac0a46fSAndroid Build Coastguard Worker 
4371*3ac0a46fSAndroid Build Coastguard Worker   // There should be no memory leaks with a call to FPDFPageObj_Destroy().
4372*3ac0a46fSAndroid Build Coastguard Worker   FPDFPageObj_Destroy(rect);
4373*3ac0a46fSAndroid Build Coastguard Worker }
4374*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GetImageFilters)4375*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GetImageFilters) {
4376*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4377*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
4378*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
4379*3ac0a46fSAndroid Build Coastguard Worker 
4380*3ac0a46fSAndroid Build Coastguard Worker   // Verify that retrieving the filter of a non-image object would fail.
4381*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 32);
4382*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_NE(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4383*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(0, FPDFImageObj_GetImageFilterCount(obj));
4384*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(0u, FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0));
4385*3ac0a46fSAndroid Build Coastguard Worker 
4386*3ac0a46fSAndroid Build Coastguard Worker   // Verify the returned filter string for an image object with a single filter.
4387*3ac0a46fSAndroid Build Coastguard Worker   obj = FPDFPage_GetObject(page, 33);
4388*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4389*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(1, FPDFImageObj_GetImageFilterCount(obj));
4390*3ac0a46fSAndroid Build Coastguard Worker   unsigned long len = FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0);
4391*3ac0a46fSAndroid Build Coastguard Worker   std::vector<char> buf(len);
4392*3ac0a46fSAndroid Build Coastguard Worker   static constexpr char kFlateDecode[] = "FlateDecode";
4393*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(sizeof(kFlateDecode),
4394*3ac0a46fSAndroid Build Coastguard Worker             FPDFImageObj_GetImageFilter(obj, 0, buf.data(), len));
4395*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_STREQ(kFlateDecode, buf.data());
4396*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(0u, FPDFImageObj_GetImageFilter(obj, 1, nullptr, 0));
4397*3ac0a46fSAndroid Build Coastguard Worker 
4398*3ac0a46fSAndroid Build Coastguard Worker   // Verify all the filters for an image object with a list of filters.
4399*3ac0a46fSAndroid Build Coastguard Worker   obj = FPDFPage_GetObject(page, 38);
4400*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4401*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(2, FPDFImageObj_GetImageFilterCount(obj));
4402*3ac0a46fSAndroid Build Coastguard Worker   len = FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0);
4403*3ac0a46fSAndroid Build Coastguard Worker   buf.clear();
4404*3ac0a46fSAndroid Build Coastguard Worker   buf.resize(len);
4405*3ac0a46fSAndroid Build Coastguard Worker   static constexpr char kASCIIHexDecode[] = "ASCIIHexDecode";
4406*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(sizeof(kASCIIHexDecode),
4407*3ac0a46fSAndroid Build Coastguard Worker             FPDFImageObj_GetImageFilter(obj, 0, buf.data(), len));
4408*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_STREQ(kASCIIHexDecode, buf.data());
4409*3ac0a46fSAndroid Build Coastguard Worker 
4410*3ac0a46fSAndroid Build Coastguard Worker   len = FPDFImageObj_GetImageFilter(obj, 1, nullptr, 0);
4411*3ac0a46fSAndroid Build Coastguard Worker   buf.clear();
4412*3ac0a46fSAndroid Build Coastguard Worker   buf.resize(len);
4413*3ac0a46fSAndroid Build Coastguard Worker   static constexpr char kDCTDecode[] = "DCTDecode";
4414*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(sizeof(kDCTDecode),
4415*3ac0a46fSAndroid Build Coastguard Worker             FPDFImageObj_GetImageFilter(obj, 1, buf.data(), len));
4416*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_STREQ(kDCTDecode, buf.data());
4417*3ac0a46fSAndroid Build Coastguard Worker 
4418*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
4419*3ac0a46fSAndroid Build Coastguard Worker }
4420*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GetImageMetadata)4421*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GetImageMetadata) {
4422*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4423*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
4424*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
4425*3ac0a46fSAndroid Build Coastguard Worker 
4426*3ac0a46fSAndroid Build Coastguard Worker   // Check that getting the metadata of a null object would fail.
4427*3ac0a46fSAndroid Build Coastguard Worker   FPDF_IMAGEOBJ_METADATA metadata;
4428*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFImageObj_GetImageMetadata(nullptr, page, &metadata));
4429*3ac0a46fSAndroid Build Coastguard Worker 
4430*3ac0a46fSAndroid Build Coastguard Worker   // Check that receiving the metadata with a null metadata object would fail.
4431*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 35);
4432*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFImageObj_GetImageMetadata(obj, page, nullptr));
4433*3ac0a46fSAndroid Build Coastguard Worker 
4434*3ac0a46fSAndroid Build Coastguard Worker   // Check that when retrieving an image object's metadata without passing in
4435*3ac0a46fSAndroid Build Coastguard Worker   // |page|, all values are correct, with the last two being default values.
4436*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4437*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, nullptr, &metadata));
4438*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(7, metadata.marked_content_id);
4439*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(92u, metadata.width);
4440*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(68u, metadata.height);
4441*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(96.0f, metadata.horizontal_dpi);
4442*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(96.0f, metadata.vertical_dpi);
4443*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(0u, metadata.bits_per_pixel);
4444*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_COLORSPACE_UNKNOWN, metadata.colorspace);
4445*3ac0a46fSAndroid Build Coastguard Worker 
4446*3ac0a46fSAndroid Build Coastguard Worker   // Verify the metadata of a bitmap image with indexed colorspace.
4447*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
4448*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(7, metadata.marked_content_id);
4449*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(92u, metadata.width);
4450*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(68u, metadata.height);
4451*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(96.0f, metadata.horizontal_dpi);
4452*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(96.0f, metadata.vertical_dpi);
4453*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(1u, metadata.bits_per_pixel);
4454*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_COLORSPACE_INDEXED, metadata.colorspace);
4455*3ac0a46fSAndroid Build Coastguard Worker 
4456*3ac0a46fSAndroid Build Coastguard Worker   // Verify the metadata of an image with RGB colorspace.
4457*3ac0a46fSAndroid Build Coastguard Worker   obj = FPDFPage_GetObject(page, 37);
4458*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4459*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
4460*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(9, metadata.marked_content_id);
4461*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(126u, metadata.width);
4462*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(106u, metadata.height);
4463*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(162.173752f, metadata.horizontal_dpi);
4464*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(162.555878f, metadata.vertical_dpi);
4465*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(24u, metadata.bits_per_pixel);
4466*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_COLORSPACE_DEVICERGB, metadata.colorspace);
4467*3ac0a46fSAndroid Build Coastguard Worker 
4468*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
4469*3ac0a46fSAndroid Build Coastguard Worker }
4470*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GetImageMetadataJpxLzw)4471*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GetImageMetadataJpxLzw) {
4472*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("jpx_lzw.pdf"));
4473*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
4474*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
4475*3ac0a46fSAndroid Build Coastguard Worker 
4476*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 0);
4477*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4478*3ac0a46fSAndroid Build Coastguard Worker 
4479*3ac0a46fSAndroid Build Coastguard Worker   FPDF_IMAGEOBJ_METADATA metadata;
4480*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
4481*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(-1, metadata.marked_content_id);
4482*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(612u, metadata.width);
4483*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(792u, metadata.height);
4484*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(72.0f, metadata.horizontal_dpi);
4485*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FLOAT_EQ(72.0f, metadata.vertical_dpi);
4486*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(24u, metadata.bits_per_pixel);
4487*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(FPDF_COLORSPACE_UNKNOWN, metadata.colorspace);
4488*3ac0a46fSAndroid Build Coastguard Worker 
4489*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
4490*3ac0a46fSAndroid Build Coastguard Worker }
4491*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GetImagePixelSize)4492*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GetImagePixelSize) {
4493*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4494*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
4495*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
4496*3ac0a46fSAndroid Build Coastguard Worker 
4497*3ac0a46fSAndroid Build Coastguard Worker   // Check that getting the size of a null object would fail.
4498*3ac0a46fSAndroid Build Coastguard Worker   unsigned int width = 0;
4499*3ac0a46fSAndroid Build Coastguard Worker   unsigned int height = 0;
4500*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFImageObj_GetImagePixelSize(nullptr, &width, &height));
4501*3ac0a46fSAndroid Build Coastguard Worker 
4502*3ac0a46fSAndroid Build Coastguard Worker   // Check that receiving the size with a null width and height pointers would
4503*3ac0a46fSAndroid Build Coastguard Worker   // fail.
4504*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 35);
4505*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4506*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFImageObj_GetImagePixelSize(obj, nullptr, nullptr));
4507*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFImageObj_GetImagePixelSize(obj, nullptr, &height));
4508*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFImageObj_GetImagePixelSize(obj, &width, nullptr));
4509*3ac0a46fSAndroid Build Coastguard Worker 
4510*3ac0a46fSAndroid Build Coastguard Worker   // Verify the pixel size of image.
4511*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFImageObj_GetImagePixelSize(obj, &width, &height));
4512*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(92u, width);
4513*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(68u, height);
4514*3ac0a46fSAndroid Build Coastguard Worker 
4515*3ac0a46fSAndroid Build Coastguard Worker   obj = FPDFPage_GetObject(page, 37);
4516*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4517*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDFImageObj_GetImagePixelSize(obj, &width, &height));
4518*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(126u, width);
4519*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_EQ(106u, height);
4520*3ac0a46fSAndroid Build Coastguard Worker 
4521*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
4522*3ac0a46fSAndroid Build Coastguard Worker }
4523*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GetRenderedBitmapForHelloWorldText)4524*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GetRenderedBitmapForHelloWorldText) {
4525*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("hello_world.pdf"));
4526*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
4527*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
4528*3ac0a46fSAndroid Build Coastguard Worker 
4529*3ac0a46fSAndroid Build Coastguard Worker   {
4530*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT text_object = FPDFPage_GetObject(page, 0);
4531*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_object));
4532*3ac0a46fSAndroid Build Coastguard Worker 
4533*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap(
4534*3ac0a46fSAndroid Build Coastguard Worker         FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 1));
4535*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(bitmap);
4536*3ac0a46fSAndroid Build Coastguard Worker     const char* checksum = []() {
4537*3ac0a46fSAndroid Build Coastguard Worker       if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
4538*3ac0a46fSAndroid Build Coastguard Worker         return "b17801afe8a36d6aad6c2239b88f2a73";
4539*3ac0a46fSAndroid Build Coastguard Worker       }
4540*3ac0a46fSAndroid Build Coastguard Worker       return "bb0abe1accca1cfeaaf78afa35762350";
4541*3ac0a46fSAndroid Build Coastguard Worker     }();
4542*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(bitmap.get(), 64, 11, checksum);
4543*3ac0a46fSAndroid Build Coastguard Worker 
4544*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap x2_bitmap(
4545*3ac0a46fSAndroid Build Coastguard Worker         FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 2.4f));
4546*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(x2_bitmap);
4547*3ac0a46fSAndroid Build Coastguard Worker     const char* x2_checksum = []() {
4548*3ac0a46fSAndroid Build Coastguard Worker       if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
4549*3ac0a46fSAndroid Build Coastguard Worker         return "33af8b151ab26ebce5a71b39eedea6b1";
4550*3ac0a46fSAndroid Build Coastguard Worker       }
4551*3ac0a46fSAndroid Build Coastguard Worker       return "80db528ec7146d92247f2339a8f10ba5";
4552*3ac0a46fSAndroid Build Coastguard Worker     }();
4553*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(x2_bitmap.get(), 153, 25, x2_checksum);
4554*3ac0a46fSAndroid Build Coastguard Worker 
4555*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap x10_bitmap(
4556*3ac0a46fSAndroid Build Coastguard Worker         FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 10));
4557*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(x10_bitmap);
4558*3ac0a46fSAndroid Build Coastguard Worker     const char* x10_checksum = []() {
4559*3ac0a46fSAndroid Build Coastguard Worker       if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
4560*3ac0a46fSAndroid Build Coastguard Worker         return "93dd7ad07bdaaba9ecd268350cb91596";
4561*3ac0a46fSAndroid Build Coastguard Worker       return "149f63de758ab01d3b75605cdfd4c176";
4562*3ac0a46fSAndroid Build Coastguard Worker     }();
4563*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(x10_bitmap.get(), 631, 103, x10_checksum);
4564*3ac0a46fSAndroid Build Coastguard Worker   }
4565*3ac0a46fSAndroid Build Coastguard Worker 
4566*3ac0a46fSAndroid Build Coastguard Worker   {
4567*3ac0a46fSAndroid Build Coastguard Worker     FPDF_PAGEOBJECT text_object = FPDFPage_GetObject(page, 1);
4568*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_object));
4569*3ac0a46fSAndroid Build Coastguard Worker 
4570*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap(
4571*3ac0a46fSAndroid Build Coastguard Worker         FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 1));
4572*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(bitmap);
4573*3ac0a46fSAndroid Build Coastguard Worker     const char* checksum = []() {
4574*3ac0a46fSAndroid Build Coastguard Worker       if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
4575*3ac0a46fSAndroid Build Coastguard Worker         return "63fd059d984a5bea10f27ba026420202";
4576*3ac0a46fSAndroid Build Coastguard Worker       }
4577*3ac0a46fSAndroid Build Coastguard Worker       return "3fc1101b2408c5484adc24ba0a11ff3d";
4578*3ac0a46fSAndroid Build Coastguard Worker     }();
4579*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(bitmap.get(), 116, 16, checksum);
4580*3ac0a46fSAndroid Build Coastguard Worker 
4581*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap x2_bitmap(
4582*3ac0a46fSAndroid Build Coastguard Worker         FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 2.4f));
4583*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(x2_bitmap);
4584*3ac0a46fSAndroid Build Coastguard Worker     const char* x2_checksum = []() {
4585*3ac0a46fSAndroid Build Coastguard Worker       if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
4586*3ac0a46fSAndroid Build Coastguard Worker         return "fc45021e3ea3ebd406fe6ffaa8c5c5b7";
4587*3ac0a46fSAndroid Build Coastguard Worker       }
4588*3ac0a46fSAndroid Build Coastguard Worker       return "429960ae7b822f0c630432535e637465";
4589*3ac0a46fSAndroid Build Coastguard Worker     }();
4590*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(x2_bitmap.get(), 276, 36, x2_checksum);
4591*3ac0a46fSAndroid Build Coastguard Worker 
4592*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap x10_bitmap(
4593*3ac0a46fSAndroid Build Coastguard Worker         FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 10));
4594*3ac0a46fSAndroid Build Coastguard Worker     ASSERT_TRUE(x10_bitmap);
4595*3ac0a46fSAndroid Build Coastguard Worker     const char* x10_checksum = []() {
4596*3ac0a46fSAndroid Build Coastguard Worker       if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
4597*3ac0a46fSAndroid Build Coastguard Worker         return "61476636eaa0da0b93d8b1937cf22b75";
4598*3ac0a46fSAndroid Build Coastguard Worker       return "f5f93bf64de579b59e775d7076ca0a5a";
4599*3ac0a46fSAndroid Build Coastguard Worker     }();
4600*3ac0a46fSAndroid Build Coastguard Worker     CompareBitmap(x10_bitmap.get(), 1143, 150, x10_checksum);
4601*3ac0a46fSAndroid Build Coastguard Worker   }
4602*3ac0a46fSAndroid Build Coastguard Worker 
4603*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
4604*3ac0a46fSAndroid Build Coastguard Worker }
4605*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GetRenderedBitmapForRotatedText)4606*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GetRenderedBitmapForRotatedText) {
4607*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("rotated_text.pdf"));
4608*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
4609*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
4610*3ac0a46fSAndroid Build Coastguard Worker 
4611*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT text_object = FPDFPage_GetObject(page, 0);
4612*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_object));
4613*3ac0a46fSAndroid Build Coastguard Worker 
4614*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFBitmap bitmap(
4615*3ac0a46fSAndroid Build Coastguard Worker       FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 1));
4616*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(bitmap);
4617*3ac0a46fSAndroid Build Coastguard Worker   const char* checksum = []() {
4618*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
4619*3ac0a46fSAndroid Build Coastguard Worker       return "f515a7209d7892065d3716ec462f5c10";
4620*3ac0a46fSAndroid Build Coastguard Worker     }
4621*3ac0a46fSAndroid Build Coastguard Worker     return "08ada0802f780d3fefb161dc6fb45977";
4622*3ac0a46fSAndroid Build Coastguard Worker   }();
4623*3ac0a46fSAndroid Build Coastguard Worker   CompareBitmap(bitmap.get(), 29, 28, checksum);
4624*3ac0a46fSAndroid Build Coastguard Worker 
4625*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFBitmap x2_bitmap(
4626*3ac0a46fSAndroid Build Coastguard Worker       FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 2.4f));
4627*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(x2_bitmap);
4628*3ac0a46fSAndroid Build Coastguard Worker   const char* x2_checksum = []() {
4629*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
4630*3ac0a46fSAndroid Build Coastguard Worker       return "c69bbe5318ec149f63228e276e708612";
4631*3ac0a46fSAndroid Build Coastguard Worker     }
4632*3ac0a46fSAndroid Build Coastguard Worker     return "09d7ddb647b8653cb59aede349a0c3e1";
4633*3ac0a46fSAndroid Build Coastguard Worker   }();
4634*3ac0a46fSAndroid Build Coastguard Worker   CompareBitmap(x2_bitmap.get(), 67, 67, x2_checksum);
4635*3ac0a46fSAndroid Build Coastguard Worker 
4636*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFBitmap x10_bitmap(
4637*3ac0a46fSAndroid Build Coastguard Worker       FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 10));
4638*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(x10_bitmap);
4639*3ac0a46fSAndroid Build Coastguard Worker   const char* x10_checksum = []() {
4640*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
4641*3ac0a46fSAndroid Build Coastguard Worker       return "bb7c2ec575f27cf882dcd38f2563c00f";
4642*3ac0a46fSAndroid Build Coastguard Worker     return "bbd3842a4b50dbfcbce4eee2b067a297";
4643*3ac0a46fSAndroid Build Coastguard Worker   }();
4644*3ac0a46fSAndroid Build Coastguard Worker   CompareBitmap(x10_bitmap.get(), 275, 275, x10_checksum);
4645*3ac0a46fSAndroid Build Coastguard Worker 
4646*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
4647*3ac0a46fSAndroid Build Coastguard Worker }
4648*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GetRenderedBitmapForColorText)4649*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GetRenderedBitmapForColorText) {
4650*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("text_color.pdf"));
4651*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
4652*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
4653*3ac0a46fSAndroid Build Coastguard Worker 
4654*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT text_object = FPDFPage_GetObject(page, 0);
4655*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_object));
4656*3ac0a46fSAndroid Build Coastguard Worker 
4657*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFBitmap bitmap(
4658*3ac0a46fSAndroid Build Coastguard Worker       FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 7.3f));
4659*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(bitmap);
4660*3ac0a46fSAndroid Build Coastguard Worker   const char* checksum = []() {
4661*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer())
4662*3ac0a46fSAndroid Build Coastguard Worker       return "1d74731d23a056c0e3fb88f2f85b2581";
4663*3ac0a46fSAndroid Build Coastguard Worker     return "e8154fa8ededf4d9b8b35b5260897b6c";
4664*3ac0a46fSAndroid Build Coastguard Worker   }();
4665*3ac0a46fSAndroid Build Coastguard Worker   CompareBitmap(bitmap.get(), 120, 186, checksum);
4666*3ac0a46fSAndroid Build Coastguard Worker 
4667*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
4668*3ac0a46fSAndroid Build Coastguard Worker }
4669*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GetRenderedBitmapForNewlyCreatedText)4670*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GetRenderedBitmapForNewlyCreatedText) {
4671*3ac0a46fSAndroid Build Coastguard Worker   // Start with a blank document.
4672*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(CreateNewDocument());
4673*3ac0a46fSAndroid Build Coastguard Worker 
4674*3ac0a46fSAndroid Build Coastguard Worker   // Create a new text object.
4675*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFPageObject text_object(
4676*3ac0a46fSAndroid Build Coastguard Worker       FPDFPageObj_NewTextObj(document(), "Arial", 12.0f));
4677*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_object.get()));
4678*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFWideString text = GetFPDFWideString(kBottomText);
4679*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_TRUE(FPDFText_SetText(text_object.get(), text.get()));
4680*3ac0a46fSAndroid Build Coastguard Worker 
4681*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFBitmap bitmap(
4682*3ac0a46fSAndroid Build Coastguard Worker       FPDFTextObj_GetRenderedBitmap(document(), nullptr, text_object.get(), 1));
4683*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(bitmap);
4684*3ac0a46fSAndroid Build Coastguard Worker   const char* checksum = []() {
4685*3ac0a46fSAndroid Build Coastguard Worker     if (CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()) {
4686*3ac0a46fSAndroid Build Coastguard Worker       return "574ae982d02e653ab6a8f23a6cdf4085";
4687*3ac0a46fSAndroid Build Coastguard Worker     }
4688*3ac0a46fSAndroid Build Coastguard Worker     return "fa947759dab76d68a07ccf6f97b2d9c2";
4689*3ac0a46fSAndroid Build Coastguard Worker   }();
4690*3ac0a46fSAndroid Build Coastguard Worker   CompareBitmap(bitmap.get(), 151, 12, checksum);
4691*3ac0a46fSAndroid Build Coastguard Worker }
4692*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,GetRenderedBitmapForTextWithBadParameters)4693*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, GetRenderedBitmapForTextWithBadParameters) {
4694*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("hello_world.pdf"));
4695*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
4696*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
4697*3ac0a46fSAndroid Build Coastguard Worker 
4698*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGEOBJECT text_object = FPDFPage_GetObject(page, 0);
4699*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(text_object);
4700*3ac0a46fSAndroid Build Coastguard Worker 
4701*3ac0a46fSAndroid Build Coastguard Worker   // Simple bad parameters testing.
4702*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(nullptr, nullptr, nullptr, 0));
4703*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(document(), nullptr, nullptr, 0));
4704*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(nullptr, page, nullptr, 0));
4705*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(nullptr, nullptr, text_object, 0));
4706*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(nullptr, nullptr, nullptr, 1));
4707*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(document(), page, nullptr, 0));
4708*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(document(), nullptr, nullptr, 1));
4709*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(nullptr, page, text_object, 0));
4710*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(nullptr, page, nullptr, 1));
4711*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(nullptr, nullptr, text_object, 1));
4712*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(document(), page, nullptr, 1));
4713*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(nullptr, page, text_object, 1));
4714*3ac0a46fSAndroid Build Coastguard Worker 
4715*3ac0a46fSAndroid Build Coastguard Worker   // Test bad scale values.
4716*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 0));
4717*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(
4718*3ac0a46fSAndroid Build Coastguard Worker       FPDFTextObj_GetRenderedBitmap(document(), page, text_object, -1));
4719*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(
4720*3ac0a46fSAndroid Build Coastguard Worker       FPDFTextObj_GetRenderedBitmap(document(), page, text_object, 10000));
4721*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(
4722*3ac0a46fSAndroid Build Coastguard Worker       document(), page, text_object, std::numeric_limits<float>::max()));
4723*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(
4724*3ac0a46fSAndroid Build Coastguard Worker       document(), page, text_object, std::numeric_limits<float>::infinity()));
4725*3ac0a46fSAndroid Build Coastguard Worker 
4726*3ac0a46fSAndroid Build Coastguard Worker   {
4727*3ac0a46fSAndroid Build Coastguard Worker     // `text_object` will render without `page`, but may not render correctly
4728*3ac0a46fSAndroid Build Coastguard Worker     // without the resources from `page`. Although it does in this simple case.
4729*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFBitmap bitmap(
4730*3ac0a46fSAndroid Build Coastguard Worker         FPDFTextObj_GetRenderedBitmap(document(), nullptr, text_object, 1));
4731*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(bitmap);
4732*3ac0a46fSAndroid Build Coastguard Worker   }
4733*3ac0a46fSAndroid Build Coastguard Worker 
4734*3ac0a46fSAndroid Build Coastguard Worker   // Mismatch between the document and the page fails too.
4735*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFDocument empty_document(FPDF_CreateNewDocument());
4736*3ac0a46fSAndroid Build Coastguard Worker   EXPECT_FALSE(FPDFTextObj_GetRenderedBitmap(empty_document.get(), page,
4737*3ac0a46fSAndroid Build Coastguard Worker                                              text_object, 1));
4738*3ac0a46fSAndroid Build Coastguard Worker 
4739*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
4740*3ac0a46fSAndroid Build Coastguard Worker }
4741*3ac0a46fSAndroid Build Coastguard Worker 
TEST_F(FPDFEditEmbedderTest,MultipleGraphicsStates)4742*3ac0a46fSAndroid Build Coastguard Worker TEST_F(FPDFEditEmbedderTest, MultipleGraphicsStates) {
4743*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(OpenDocument("multiple_graphics_states.pdf"));
4744*3ac0a46fSAndroid Build Coastguard Worker   FPDF_PAGE page = LoadPage(0);
4745*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(page);
4746*3ac0a46fSAndroid Build Coastguard Worker 
4747*3ac0a46fSAndroid Build Coastguard Worker   {
4748*3ac0a46fSAndroid Build Coastguard Worker     ScopedFPDFPageObject path(FPDFPageObj_CreateNewPath(400, 100));
4749*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPageObj_SetFillColor(path.get(), 255, 0, 0, 255));
4750*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPath_SetDrawMode(path.get(), FPDF_FILLMODE_ALTERNATE, 0));
4751*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPath_MoveTo(path.get(), 100, 100));
4752*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPath_LineTo(path.get(), 100, 125));
4753*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPath_Close(path.get()));
4754*3ac0a46fSAndroid Build Coastguard Worker 
4755*3ac0a46fSAndroid Build Coastguard Worker     FPDFPage_InsertObject(page, path.release());
4756*3ac0a46fSAndroid Build Coastguard Worker     EXPECT_TRUE(FPDFPage_GenerateContent(page));
4757*3ac0a46fSAndroid Build Coastguard Worker   }
4758*3ac0a46fSAndroid Build Coastguard Worker 
4759*3ac0a46fSAndroid Build Coastguard Worker   const char* checksum = CFX_DefaultRenderDevice::SkiaIsDefaultRenderer()
4760*3ac0a46fSAndroid Build Coastguard Worker                              ? "7ebec75d95c64b522999a710de76c52c"
4761*3ac0a46fSAndroid Build Coastguard Worker                              : "f4b36616a7fea81a4f06cc7b01a55ac1";
4762*3ac0a46fSAndroid Build Coastguard Worker 
4763*3ac0a46fSAndroid Build Coastguard Worker   ScopedFPDFBitmap bitmap = RenderPage(page);
4764*3ac0a46fSAndroid Build Coastguard Worker   CompareBitmap(bitmap.get(), 200, 300, checksum);
4765*3ac0a46fSAndroid Build Coastguard Worker 
4766*3ac0a46fSAndroid Build Coastguard Worker   ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
4767*3ac0a46fSAndroid Build Coastguard Worker   VerifySavedDocument(200, 300, checksum);
4768*3ac0a46fSAndroid Build Coastguard Worker 
4769*3ac0a46fSAndroid Build Coastguard Worker   UnloadPage(page);
4770*3ac0a46fSAndroid Build Coastguard Worker }
4771