blob: cd8cec98ddabdb9046d878496cd61ff63906cc3c [file] [log] [blame]
Tom Sepezd483eb42016-01-06 10:03:59 -08001// Copyright 2016 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Dan Sinclair85c8e7f2016-11-21 13:50:32 -05005#include <memory>
6#include <string>
Nicolas Penad03ca422017-03-06 13:54:33 -05007#include <utility>
Jane Liu548334e2017-08-03 16:33:40 -04008#include <vector>
Dan Sinclair85c8e7f2016-11-21 13:50:32 -05009
Lei Zhange4cdac52019-04-30 16:45:57 +000010#include "build/build_config.h"
Nicolas Penabe90aae2017-02-27 10:41:41 -050011#include "core/fpdfapi/font/cpdf_font.h"
Nicolas Penaa4ad01f2017-02-15 16:26:48 -050012#include "core/fpdfapi/page/cpdf_page.h"
Henrique Nakashima6eb79392018-06-12 20:27:35 +000013#include "core/fpdfapi/page/cpdf_pageobject.h"
Nicolas Penabe90aae2017-02-27 10:41:41 -050014#include "core/fpdfapi/parser/cpdf_array.h"
Nicolas Penaa4ad01f2017-02-15 16:26:48 -050015#include "core/fpdfapi/parser/cpdf_dictionary.h"
Nicolas Penad03ca422017-03-06 13:54:33 -050016#include "core/fpdfapi/parser/cpdf_number.h"
Nicolas Penabe90aae2017-02-27 10:41:41 -050017#include "core/fpdfapi/parser/cpdf_stream.h"
Artem Strygineababa12018-06-06 12:31:18 +000018#include "core/fpdfapi/parser/cpdf_stream_acc.h"
Tom Sepez6c57cda2021-07-23 19:41:57 +000019#include "core/fxcrt/fx_codepage.h"
Nicolas Pena0fc185e2017-02-08 12:13:20 -050020#include "core/fxcrt/fx_system.h"
Lei Zhang0dcb8fd2019-02-07 00:46:04 +000021#include "core/fxge/fx_font.h"
Dan Sinclair00d47a62018-03-28 18:39:04 +000022#include "fpdfsdk/cpdfsdk_helpers.h"
Tom Sepeze08d2b12018-04-25 18:49:32 +000023#include "public/cpp/fpdf_scopers.h"
Jane Liueda65252017-06-07 11:31:27 -040024#include "public/fpdf_annot.h"
Tom Sepezd483eb42016-01-06 10:03:59 -080025#include "public/fpdf_edit.h"
26#include "public/fpdfview.h"
27#include "testing/embedder_test.h"
Hui Yingstb4baceb2020-04-28 23:46:10 +000028#include "testing/embedder_test_constants.h"
Lei Zhangb6992dd2019-02-05 23:30:20 +000029#include "testing/fx_string_testhelpers.h"
Tom Sepez0aec19b2016-01-07 12:22:44 -080030#include "testing/gmock/include/gmock/gmock-matchers.h"
Tom Sepezd483eb42016-01-06 10:03:59 -080031#include "testing/gtest/include/gtest/gtest.h"
Hui Yingst8e88e382020-11-02 18:19:56 +000032#include "testing/utils/file_util.h"
Lei Zhang4c64e962019-02-05 19:24:12 +000033#include "testing/utils/hash.h"
Hui Yingst8e88e382020-11-02 18:19:56 +000034#include "testing/utils/path_service.h"
Tom Sepez9c78c0d2021-01-27 20:13:14 +000035#include "third_party/base/check.h"
Tom Sepezd483eb42016-01-06 10:03:59 -080036
Hui Yingstb4baceb2020-04-28 23:46:10 +000037using pdfium::kHelloWorldChecksum;
38
39namespace {
40
Hui Yingst3b6136a2020-06-09 00:39:33 +000041const char kAllRemovedChecksum[] = "eee4600ac08b458ac7ac2320e225674c";
42
43const wchar_t kBottomText[] = L"I'm at the bottom of the page";
44
Hui Yingstbf9eee12022-05-25 21:20:24 +000045#if BUILDFLAG(IS_APPLE) && !defined(_SKIA_SUPPORT_) && \
46 !defined(_SKIA_SUPPORT_PATHS_)
Hui Yingst5ce6a3f2020-11-11 02:29:09 +000047static constexpr char kBottomTextChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +000048 "81636489006a31fcb00cf29efcdf7909";
Hui Yingst5ce6a3f2020-11-11 02:29:09 +000049#else
50static constexpr char kBottomTextChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +000051 "891dcb6e914c8360998055f1f47c9727";
Hui Yingst3b6136a2020-06-09 00:39:33 +000052#endif
Hui Yingstb4baceb2020-04-28 23:46:10 +000053
Hui Yingstbf9eee12022-05-25 21:20:24 +000054#if BUILDFLAG(IS_APPLE) && !defined(_SKIA_SUPPORT_) && \
55 !defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +000056const char kFirstRemovedChecksum[] = "a1dc2812692fcc7ee4f01ca77435df9d";
Hui Yingstb4baceb2020-04-28 23:46:10 +000057#else
Tom Andersond4fe5f72021-12-03 20:52:52 +000058const char kFirstRemovedChecksum[] = "e1477dc3b5b3b9c560814c4d1135a02b";
Hui Yingstb4baceb2020-04-28 23:46:10 +000059#endif
60
Hui Yingst3b6136a2020-06-09 00:39:33 +000061const wchar_t kLoadedFontText[] = L"I am testing my loaded font, WEE.";
62
Hui Yingst9d6ec8f2020-11-05 23:35:38 +000063#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Hui Yingste1215fc2022-03-26 22:29:08 +000064const char kLoadedFontTextChecksum[] = "d58570cc045dfb818b92cbabbd1a364c";
Lei Zhang42d30c22022-01-12 19:24:43 +000065#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +000066const char kLoadedFontTextChecksum[] = "0f3e4a7d71f9e7eb8a1a0d69403b9848";
Hui Yingst3b6136a2020-06-09 00:39:33 +000067#else
Tom Andersond4fe5f72021-12-03 20:52:52 +000068const char kLoadedFontTextChecksum[] = "d58570cc045dfb818b92cbabbd1a364c";
Hui Yingst3b6136a2020-06-09 00:39:33 +000069#endif
70
71const char kRedRectangleChecksum[] = "66d02eaa6181e2c069ce2ea99beda497";
72
Lei Zhang85166512020-07-14 23:28:56 +000073// In embedded_images.pdf.
74const char kEmbeddedImage33Checksum[] = "cb3637934bb3b95a6e4ae1ea9eb9e56e";
75
Hui Yingstb4baceb2020-04-28 23:46:10 +000076} // namespace
77
Lei Zhangab41f252018-12-23 03:10:50 +000078class FPDFEditEmbedderTest : public EmbedderTest {
Nicolas Penad03ca422017-03-06 13:54:33 -050079 protected:
80 FPDF_DOCUMENT CreateNewDocument() {
Lei Zhang935fb862021-11-05 00:15:05 +000081 CreateEmptyDocumentWithoutFormFillEnvironment();
Lei Zhang38e2b0e2021-11-05 00:28:05 +000082 cpdf_doc_ = CPDFDocumentFromFPDFDocument(document());
83 return document();
Nicolas Penad03ca422017-03-06 13:54:33 -050084 }
85
Lei Zhang710fa992018-05-25 16:24:48 +000086 void CheckFontDescriptor(const CPDF_Dictionary* font_dict,
Nicolas Penad03ca422017-03-06 13:54:33 -050087 int font_type,
88 bool bold,
89 bool italic,
Tom Sepez20c41a52018-08-29 23:53:53 +000090 pdfium::span<const uint8_t> span) {
Lei Zhangb1ec2802018-05-25 21:55:24 +000091 const CPDF_Dictionary* font_desc = font_dict->GetDictFor("FontDescriptor");
Nicolas Penad03ca422017-03-06 13:54:33 -050092 ASSERT_TRUE(font_desc);
Lei Zhanga228ff32020-06-24 17:39:33 +000093 EXPECT_EQ("FontDescriptor", font_desc->GetNameFor("Type"));
94 ByteString font_name = font_desc->GetNameFor("FontName");
95 EXPECT_FALSE(font_name.IsEmpty());
96 EXPECT_EQ(font_dict->GetNameFor("BaseFont"), font_name);
Nicolas Penad03ca422017-03-06 13:54:33 -050097
98 // Check that the font descriptor has the required keys according to spec
99 // 1.7 Table 5.19
100 ASSERT_TRUE(font_desc->KeyExist("Flags"));
Dan Sinclair10e1f052017-09-28 15:59:42 -0400101
Nicolas Penad03ca422017-03-06 13:54:33 -0500102 int font_flags = font_desc->GetIntegerFor("Flags");
Lei Zhang44d03832019-10-18 18:45:31 +0000103 EXPECT_EQ(bold, FontStyleIsForceBold(font_flags));
Dan Sinclair10e1f052017-09-28 15:59:42 -0400104 EXPECT_EQ(italic, FontStyleIsItalic(font_flags));
105 EXPECT_TRUE(FontStyleIsNonSymbolic(font_flags));
Nicolas Penad03ca422017-03-06 13:54:33 -0500106 ASSERT_TRUE(font_desc->KeyExist("FontBBox"));
Nicolás Peña5f95f362017-09-28 13:00:45 +0900107
Lei Zhangb1ec2802018-05-25 21:55:24 +0000108 const CPDF_Array* fontBBox = font_desc->GetArrayFor("FontBBox");
Nicolás Peña5f95f362017-09-28 13:00:45 +0900109 ASSERT_TRUE(fontBBox);
Lei Zhangf40380f2018-10-12 18:31:51 +0000110 EXPECT_EQ(4u, fontBBox->size());
Nicolás Peña5f95f362017-09-28 13:00:45 +0900111 // Check that the coordinates are in the preferred order according to spec
112 // 1.7 Section 3.8.4
113 EXPECT_TRUE(fontBBox->GetIntegerAt(0) < fontBBox->GetIntegerAt(2));
114 EXPECT_TRUE(fontBBox->GetIntegerAt(1) < fontBBox->GetIntegerAt(3));
115
Nicolas Penad03ca422017-03-06 13:54:33 -0500116 EXPECT_TRUE(font_desc->KeyExist("ItalicAngle"));
117 EXPECT_TRUE(font_desc->KeyExist("Ascent"));
118 EXPECT_TRUE(font_desc->KeyExist("Descent"));
119 EXPECT_TRUE(font_desc->KeyExist("CapHeight"));
120 EXPECT_TRUE(font_desc->KeyExist("StemV"));
Ryan Harrison275e2602017-09-18 14:23:18 -0400121 ByteString present("FontFile");
122 ByteString absent("FontFile2");
Nicolas Penad03ca422017-03-06 13:54:33 -0500123 if (font_type == FPDF_FONT_TRUETYPE)
124 std::swap(present, absent);
125 EXPECT_TRUE(font_desc->KeyExist(present));
126 EXPECT_FALSE(font_desc->KeyExist(absent));
127
Artem Strygineababa12018-06-06 12:31:18 +0000128 auto streamAcc =
129 pdfium::MakeRetain<CPDF_StreamAcc>(font_desc->GetStreamFor(present));
130 streamAcc->LoadAllDataRaw();
131
Nicolas Penad03ca422017-03-06 13:54:33 -0500132 // Check that the font stream is the one that was provided
Tom Sepez20c41a52018-08-29 23:53:53 +0000133 ASSERT_EQ(span.size(), streamAcc->GetSize());
Nicolás Peña79eab232017-09-28 13:29:05 +0900134 if (font_type == FPDF_FONT_TRUETYPE) {
Tom Sepez20c41a52018-08-29 23:53:53 +0000135 ASSERT_EQ(static_cast<int>(span.size()),
Artem Strygineababa12018-06-06 12:31:18 +0000136 streamAcc->GetDict()->GetIntegerFor("Length1"));
Nicolás Peña79eab232017-09-28 13:29:05 +0900137 }
Artem Strygineababa12018-06-06 12:31:18 +0000138
139 const uint8_t* stream_data = streamAcc->GetData();
Tom Sepez20c41a52018-08-29 23:53:53 +0000140 for (size_t j = 0; j < span.size(); j++)
141 EXPECT_EQ(span[j], stream_data[j]) << " at byte " << j;
Nicolas Penad03ca422017-03-06 13:54:33 -0500142 }
143
Lei Zhangde579ab2018-05-25 21:49:49 +0000144 void CheckCompositeFontWidths(const CPDF_Array* widths_array,
Nicolas Penad03ca422017-03-06 13:54:33 -0500145 CPDF_Font* typed_font) {
146 // Check that W array is in a format that conforms to PDF spec 1.7 section
147 // "Glyph Metrics in CIDFonts" (these checks are not
148 // implementation-specific).
Lei Zhangf40380f2018-10-12 18:31:51 +0000149 EXPECT_GT(widths_array->size(), 1u);
Nicolas Penad03ca422017-03-06 13:54:33 -0500150 int num_cids_checked = 0;
151 int cur_cid = 0;
Lei Zhangf40380f2018-10-12 18:31:51 +0000152 for (size_t idx = 0; idx < widths_array->size(); idx++) {
Nicolas Penad03ca422017-03-06 13:54:33 -0500153 int cid = widths_array->GetNumberAt(idx);
154 EXPECT_GE(cid, cur_cid);
Lei Zhangf40380f2018-10-12 18:31:51 +0000155 ASSERT_FALSE(++idx == widths_array->size());
Lei Zhangde579ab2018-05-25 21:49:49 +0000156 const CPDF_Object* next = widths_array->GetObjectAt(idx);
Nicolas Penad03ca422017-03-06 13:54:33 -0500157 if (next->IsArray()) {
158 // We are in the c [w1 w2 ...] case
Lei Zhangde579ab2018-05-25 21:49:49 +0000159 const CPDF_Array* arr = next->AsArray();
Lei Zhangf40380f2018-10-12 18:31:51 +0000160 int cnt = static_cast<int>(arr->size());
Nicolas Penad03ca422017-03-06 13:54:33 -0500161 size_t inner_idx = 0;
162 for (cur_cid = cid; cur_cid < cid + cnt; cur_cid++) {
Lei Zhang70e66192020-09-18 20:50:51 +0000163 int width = arr->GetNumberAt(inner_idx++);
Dan Sinclair971a6742018-03-28 19:23:25 +0000164 EXPECT_EQ(width, typed_font->GetCharWidthF(cur_cid))
165 << " at cid " << cur_cid;
Nicolas Penad03ca422017-03-06 13:54:33 -0500166 }
167 num_cids_checked += cnt;
168 continue;
169 }
170 // Otherwise, are in the c_first c_last w case.
171 ASSERT_TRUE(next->IsNumber());
172 int last_cid = next->AsNumber()->GetInteger();
Lei Zhangf40380f2018-10-12 18:31:51 +0000173 ASSERT_FALSE(++idx == widths_array->size());
Lei Zhang70e66192020-09-18 20:50:51 +0000174 int width = widths_array->GetNumberAt(idx);
Nicolas Penad03ca422017-03-06 13:54:33 -0500175 for (cur_cid = cid; cur_cid <= last_cid; cur_cid++) {
Dan Sinclair971a6742018-03-28 19:23:25 +0000176 EXPECT_EQ(width, typed_font->GetCharWidthF(cur_cid))
177 << " at cid " << cur_cid;
Nicolas Penad03ca422017-03-06 13:54:33 -0500178 }
179 num_cids_checked += last_cid - cid + 1;
180 }
181 // Make sure we have a good amount of cids described
Tom Andersond4fe5f72021-12-03 20:52:52 +0000182 EXPECT_GT(num_cids_checked, 200);
Nicolas Penad03ca422017-03-06 13:54:33 -0500183 }
184 CPDF_Document* cpdf_doc() { return cpdf_doc_; }
185
186 private:
187 CPDF_Document* cpdf_doc_;
188};
Tom Sepezd483eb42016-01-06 10:03:59 -0800189
etienneb7712c262016-04-26 08:13:45 -0700190namespace {
thestigdc7ec032016-11-21 15:32:52 -0800191
etienneb7712c262016-04-26 08:13:45 -0700192const char kExpectedPDF[] =
193 "%PDF-1.7\r\n"
194 "%\xA1\xB3\xC5\xD7\r\n"
195 "1 0 obj\r\n"
196 "<</Pages 2 0 R /Type/Catalog>>\r\n"
197 "endobj\r\n"
198 "2 0 obj\r\n"
199 "<</Count 1/Kids\\[ 4 0 R \\]/Type/Pages>>\r\n"
200 "endobj\r\n"
201 "3 0 obj\r\n"
202 "<</CreationDate\\(D:.*\\)/Creator\\(PDFium\\)>>\r\n"
203 "endobj\r\n"
204 "4 0 obj\r\n"
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -0400205 "<</MediaBox\\[ 0 0 640 480\\]/Parent 2 0 R "
206 "/Resources<</ExtGState<</FXE1 5 0 R >>>>"
Nicolas Penad9d6c292017-06-06 16:12:10 -0400207 "/Rotate 0/Type/Page"
etienneb7712c262016-04-26 08:13:45 -0700208 ">>\r\n"
209 "endobj\r\n"
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -0400210 "5 0 obj\r\n"
211 "<</BM/Normal/CA 1/ca 1>>\r\n"
212 "endobj\r\n"
etienneb7712c262016-04-26 08:13:45 -0700213 "xref\r\n"
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -0400214 "0 6\r\n"
etienneb7712c262016-04-26 08:13:45 -0700215 "0000000000 65535 f\r\n"
216 "0000000017 00000 n\r\n"
217 "0000000066 00000 n\r\n"
218 "0000000122 00000 n\r\n"
219 "0000000192 00000 n\r\n"
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -0400220 "0000000311 00000 n\r\n"
etienneb7712c262016-04-26 08:13:45 -0700221 "trailer\r\n"
222 "<<\r\n"
223 "/Root 1 0 R\r\n"
224 "/Info 3 0 R\r\n"
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -0400225 "/Size 6/ID\\[<.*><.*>\\]>>\r\n"
etienneb7712c262016-04-26 08:13:45 -0700226 "startxref\r\n"
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -0400227 "354\r\n"
etienneb7712c262016-04-26 08:13:45 -0700228 "%%EOF\r\n";
thestigdc7ec032016-11-21 15:32:52 -0800229
etienneb7712c262016-04-26 08:13:45 -0700230} // namespace
231
Hui Yingst8e88e382020-11-02 18:19:56 +0000232TEST_F(FPDFEditEmbedderTest, EmbedNotoSansSCFont) {
Lei Zhangb8b4a042021-11-05 00:04:25 +0000233 CreateEmptyDocument();
Hui Yingst8e88e382020-11-02 18:19:56 +0000234 ScopedFPDFPage page(FPDFPage_New(document(), 0, 400, 400));
235 std::string font_path;
Hui Yingst8532ef02020-11-04 19:17:17 +0000236 ASSERT_TRUE(PathService::GetThirdPartyFilePath(
237 "NotoSansCJK/NotoSansSC-Regular.subset.otf", &font_path));
Hui Yingst8e88e382020-11-02 18:19:56 +0000238
239 size_t file_length = 0;
240 std::unique_ptr<char, pdfium::FreeDeleter> font_data =
241 GetFileContents(font_path.c_str(), &file_length);
Lei Zhang786544d2021-07-27 21:25:24 +0000242 ASSERT_TRUE(font_data);
Hui Yingst8e88e382020-11-02 18:19:56 +0000243
244 ScopedFPDFFont font(FPDFText_LoadFont(
245 document(), reinterpret_cast<const uint8_t*>(font_data.get()),
246 file_length, FPDF_FONT_TRUETYPE, /*cid=*/true));
247 FPDF_PAGEOBJECT text_object =
248 FPDFPageObj_CreateTextObj(document(), font.get(), 20.0f);
249 EXPECT_TRUE(text_object);
250
251 // Test the characters which are either mapped to one single unicode or
252 // multiple unicodes in the embedded font.
253 ScopedFPDFWideString text = GetFPDFWideString(L"这是第一句。 这是第二行。");
254 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
255
256 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 50, 200);
257 FPDFPage_InsertObject(page.get(), text_object);
258 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
259
Hui Yingst8e88e382020-11-02 18:19:56 +0000260 const char kChecksum[] = "9a31fb87d1c6d2346bba22d1196041cd";
Hui Yingst8e88e382020-11-02 18:19:56 +0000261 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
262 CompareBitmap(page_bitmap.get(), 400, 400, kChecksum);
263
Lei Zhang786544d2021-07-27 21:25:24 +0000264 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
265 VerifySavedDocument(400, 400, kChecksum);
266}
267
268TEST_F(FPDFEditEmbedderTest, EmbedNotoSansSCFontWithCharcodes) {
Lei Zhangb8b4a042021-11-05 00:04:25 +0000269 CreateEmptyDocument();
Lei Zhang786544d2021-07-27 21:25:24 +0000270 ScopedFPDFPage page(FPDFPage_New(document(), 0, 400, 400));
271 std::string font_path;
272 ASSERT_TRUE(PathService::GetThirdPartyFilePath(
273 "NotoSansCJK/NotoSansSC-Regular.subset.otf", &font_path));
274
275 size_t file_length = 0;
276 std::unique_ptr<char, pdfium::FreeDeleter> font_data =
277 GetFileContents(font_path.c_str(), &file_length);
278 ASSERT_TRUE(font_data);
279
280 ScopedFPDFFont font(FPDFText_LoadFont(
281 document(), reinterpret_cast<const uint8_t*>(font_data.get()),
282 file_length, FPDF_FONT_TRUETYPE, /*cid=*/true));
283 FPDF_PAGEOBJECT text_object =
284 FPDFPageObj_CreateTextObj(document(), font.get(), 20.0f);
285 EXPECT_TRUE(text_object);
286
287 // Same as `text` in the EmbedNotoSansSCFont test case above.
288 const std::vector<uint32_t> charcodes = {9, 6, 7, 3, 5, 2, 1,
289 9, 6, 7, 4, 8, 2};
290 EXPECT_TRUE(
291 FPDFText_SetCharcodes(text_object, charcodes.data(), charcodes.size()));
292
293 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 50, 200);
294 FPDFPage_InsertObject(page.get(), text_object);
295 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
296
Lei Zhang786544d2021-07-27 21:25:24 +0000297 const char kChecksum[] = "9a31fb87d1c6d2346bba22d1196041cd";
Lei Zhang786544d2021-07-27 21:25:24 +0000298 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
299 CompareBitmap(page_bitmap.get(), 400, 400, kChecksum);
300
301 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Hui Yingst8e88e382020-11-02 18:19:56 +0000302 VerifySavedDocument(400, 400, kChecksum);
303}
304
Lei Zhangab41f252018-12-23 03:10:50 +0000305TEST_F(FPDFEditEmbedderTest, EmptyCreation) {
Lei Zhangb8b4a042021-11-05 00:04:25 +0000306 CreateEmptyDocument();
weili9b777de2016-08-19 16:19:46 -0700307 FPDF_PAGE page = FPDFPage_New(document(), 0, 640.0, 480.0);
Tom Sepezd483eb42016-01-06 10:03:59 -0800308 EXPECT_NE(nullptr, page);
Nicolas Penad9d6c292017-06-06 16:12:10 -0400309 // The FPDFPage_GenerateContent call should do nothing.
Tom Sepezd483eb42016-01-06 10:03:59 -0800310 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Tom Sepez0aec19b2016-01-07 12:22:44 -0800311 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
etienneb7712c262016-04-26 08:13:45 -0700312
Nicolas Penad9d6c292017-06-06 16:12:10 -0400313 EXPECT_THAT(GetString(), testing::MatchesRegex(std::string(
314 kExpectedPDF, sizeof(kExpectedPDF))));
weili9b777de2016-08-19 16:19:46 -0700315 FPDF_ClosePage(page);
Tom Sepezd483eb42016-01-06 10:03:59 -0800316}
thestigdc7ec032016-11-21 15:32:52 -0800317
318// Regression test for https://crbug.com/667012
Lei Zhangab41f252018-12-23 03:10:50 +0000319TEST_F(FPDFEditEmbedderTest, RasterizePDF) {
thestigdc7ec032016-11-21 15:32:52 -0800320 const char kAllBlackMd5sum[] = "5708fc5c4a8bd0abde99c8e8f0390615";
321
Lei Zhangf0542892019-01-17 18:46:27 +0000322 // Get the bitmap for the original document.
Tom Sepeze08d2b12018-04-25 18:49:32 +0000323 ScopedFPDFBitmap orig_bitmap;
thestigdc7ec032016-11-21 15:32:52 -0800324 {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +0000325 ASSERT_TRUE(OpenDocument("black.pdf"));
thestigdc7ec032016-11-21 15:32:52 -0800326 FPDF_PAGE orig_page = LoadPage(0);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000327 ASSERT_TRUE(orig_page);
328 orig_bitmap = RenderLoadedPage(orig_page);
329 CompareBitmap(orig_bitmap.get(), 612, 792, kAllBlackMd5sum);
thestigdc7ec032016-11-21 15:32:52 -0800330 UnloadPage(orig_page);
331 }
332
333 // Create a new document from |orig_bitmap| and save it.
334 {
335 FPDF_DOCUMENT temp_doc = FPDF_CreateNewDocument();
336 FPDF_PAGE temp_page = FPDFPage_New(temp_doc, 0, 612, 792);
337
338 // Add the bitmap to an image object and add the image object to the output
339 // page.
Lei Zhangcbd89572017-03-15 17:35:47 -0700340 FPDF_PAGEOBJECT temp_img = FPDFPageObj_NewImageObj(temp_doc);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000341 EXPECT_TRUE(
342 FPDFImageObj_SetBitmap(&temp_page, 1, temp_img, orig_bitmap.get()));
Lei Zhangc8601bf2021-06-29 23:19:27 +0000343 static constexpr FS_MATRIX kLetterScaleMatrix{612, 0, 0, 792, 0, 0};
344 EXPECT_TRUE(FPDFPageObj_SetMatrix(temp_img, &kLetterScaleMatrix));
thestigdc7ec032016-11-21 15:32:52 -0800345 FPDFPage_InsertObject(temp_page, temp_img);
346 EXPECT_TRUE(FPDFPage_GenerateContent(temp_page));
347 EXPECT_TRUE(FPDF_SaveAsCopy(temp_doc, this, 0));
348 FPDF_ClosePage(temp_page);
349 FPDF_CloseDocument(temp_doc);
350 }
thestigdc7ec032016-11-21 15:32:52 -0800351
352 // Get the generated content. Make sure it is at least as big as the original
353 // PDF.
Lei Zhangd72fd582018-07-27 19:37:27 +0000354 EXPECT_GT(GetString().size(), 923u);
Dan Sinclair04e4dc82017-10-18 12:17:14 -0400355 VerifySavedDocument(612, 792, kAllBlackMd5sum);
thestigdc7ec032016-11-21 15:32:52 -0800356}
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500357
Hui Yingsta929df72021-02-26 23:56:18 +0000358TEST_F(FPDFEditEmbedderTest, AddPaths) {
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500359 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -0500360 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000361 ASSERT_TRUE(page);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500362
363 // We will first add a red rectangle
364 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000365 ASSERT_TRUE(red_rect);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500366 // Expect false when trying to set colors out of range
Lei Zhang3475b482019-05-13 18:30:57 +0000367 EXPECT_FALSE(FPDFPageObj_SetStrokeColor(red_rect, 100, 100, 100, 300));
368 EXPECT_FALSE(FPDFPageObj_SetFillColor(red_rect, 200, 256, 200, 0));
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500369
370 // Fill rectangle with red and insert to the page
Lei Zhang3475b482019-05-13 18:30:57 +0000371 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500372 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
Miklos Vajna491112b2018-05-30 13:30:10 +0000373
374 int fillmode = FPDF_FILLMODE_NONE;
375 FPDF_BOOL stroke = true;
376 EXPECT_TRUE(FPDFPath_GetDrawMode(red_rect, &fillmode, &stroke));
377 EXPECT_EQ(FPDF_FILLMODE_ALTERNATE, fillmode);
378 EXPECT_FALSE(stroke);
379
Lei Zhangc8601bf2021-06-29 23:19:27 +0000380 static constexpr FS_MATRIX kMatrix = {1, 2, 3, 4, 5, 6};
381 EXPECT_TRUE(FPDFPageObj_SetMatrix(red_rect, &kMatrix));
Lei Zhang8da98232019-12-11 23:29:33 +0000382
383 FS_MATRIX matrix;
Lei Zhangc8601bf2021-06-29 23:19:27 +0000384 EXPECT_TRUE(FPDFPageObj_GetMatrix(red_rect, &matrix));
Lei Zhang8da98232019-12-11 23:29:33 +0000385 EXPECT_FLOAT_EQ(1.0f, matrix.a);
386 EXPECT_FLOAT_EQ(2.0f, matrix.b);
387 EXPECT_FLOAT_EQ(3.0f, matrix.c);
388 EXPECT_FLOAT_EQ(4.0f, matrix.d);
389 EXPECT_FLOAT_EQ(5.0f, matrix.e);
390 EXPECT_FLOAT_EQ(6.0f, matrix.f);
391
392 // Set back the identity matrix.
393 matrix = {1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f};
Lei Zhangc8601bf2021-06-29 23:19:27 +0000394 EXPECT_TRUE(FPDFPageObj_SetMatrix(red_rect, &matrix));
Miklos Vajna97f4d672018-06-04 14:47:17 +0000395
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500396 FPDFPage_InsertObject(page, red_rect);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000397 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000398 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +0000399 CompareBitmap(page_bitmap.get(), 612, 792, kRedRectangleChecksum);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000400 }
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500401
402 // Now add to that a green rectangle with some medium alpha
403 FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(100, 100, 40, 40);
Lei Zhang3475b482019-05-13 18:30:57 +0000404 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_rect, 0, 255, 0, 128));
Miklos Vajnaed4705b2017-04-05 09:24:50 +0200405
Miklos Vajna1ef04c92017-05-08 18:14:19 +0200406 // Make sure the type of the rectangle is a path.
407 EXPECT_EQ(FPDF_PAGEOBJ_PATH, FPDFPageObj_GetType(green_rect));
408
Miklos Vajnaed4705b2017-04-05 09:24:50 +0200409 // Make sure we get back the same color we set previously.
410 unsigned int R;
411 unsigned int G;
412 unsigned int B;
413 unsigned int A;
Lei Zhang3475b482019-05-13 18:30:57 +0000414 EXPECT_TRUE(FPDFPageObj_GetFillColor(green_rect, &R, &G, &B, &A));
Lei Zhangd72fd582018-07-27 19:37:27 +0000415 EXPECT_EQ(0u, R);
416 EXPECT_EQ(255u, G);
417 EXPECT_EQ(0u, B);
418 EXPECT_EQ(128u, A);
Miklos Vajnaed4705b2017-04-05 09:24:50 +0200419
Lei Zhang9b4b8df2021-06-12 06:38:48 +0000420 // Make sure the path has 5 points (1 CFX_Path::Point::Type::kMove and 4
421 // CFX_Path::Point::Type::kLine).
Miklos Vajna0150a542017-09-21 21:46:56 +0200422 ASSERT_EQ(5, FPDFPath_CountSegments(green_rect));
Miklos Vajna36eed872017-09-20 22:52:43 +0200423 // Verify actual coordinates.
424 FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(green_rect, 0);
425 float x;
426 float y;
427 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
428 EXPECT_EQ(100, x);
429 EXPECT_EQ(100, y);
430 EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
431 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
432 segment = FPDFPath_GetPathSegment(green_rect, 1);
433 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
434 EXPECT_EQ(100, x);
435 EXPECT_EQ(140, y);
436 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
437 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
438 segment = FPDFPath_GetPathSegment(green_rect, 2);
439 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
440 EXPECT_EQ(140, x);
441 EXPECT_EQ(140, y);
442 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
443 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
444 segment = FPDFPath_GetPathSegment(green_rect, 3);
445 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
446 EXPECT_EQ(140, x);
447 EXPECT_EQ(100, y);
448 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
449 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
450 segment = FPDFPath_GetPathSegment(green_rect, 4);
451 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
452 EXPECT_EQ(100, x);
453 EXPECT_EQ(100, y);
454 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
455 EXPECT_TRUE(FPDFPathSegment_GetClose(segment));
Miklos Vajna12abfd02017-09-15 07:49:03 +0200456
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500457 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_WINDING, 0));
458 FPDFPage_InsertObject(page, green_rect);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000459 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000460 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000461 CompareBitmap(page_bitmap.get(), 612, 792,
462 "7b0b87604594e773add528fae567a558");
463 }
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500464
465 // Add a black triangle.
466 FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(400, 100);
Lei Zhang3475b482019-05-13 18:30:57 +0000467 EXPECT_TRUE(FPDFPageObj_SetFillColor(black_path, 0, 0, 0, 200));
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500468 EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
469 EXPECT_TRUE(FPDFPath_LineTo(black_path, 400, 200));
470 EXPECT_TRUE(FPDFPath_LineTo(black_path, 300, 100));
471 EXPECT_TRUE(FPDFPath_Close(black_path));
Miklos Vajna12abfd02017-09-15 07:49:03 +0200472
Lei Zhang9b4b8df2021-06-12 06:38:48 +0000473 // Make sure the path has 3 points (1 CFX_Path::Point::Type::kMove and 2
474 // CFX_Path::Point::Type::kLine).
Miklos Vajna0150a542017-09-21 21:46:56 +0200475 ASSERT_EQ(3, FPDFPath_CountSegments(black_path));
Miklos Vajna36eed872017-09-20 22:52:43 +0200476 // Verify actual coordinates.
477 segment = FPDFPath_GetPathSegment(black_path, 0);
478 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
479 EXPECT_EQ(400, x);
480 EXPECT_EQ(100, y);
481 EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
482 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
483 segment = FPDFPath_GetPathSegment(black_path, 1);
484 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
485 EXPECT_EQ(400, x);
486 EXPECT_EQ(200, y);
487 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
488 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
489 segment = FPDFPath_GetPathSegment(black_path, 2);
490 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
491 EXPECT_EQ(300, x);
492 EXPECT_EQ(100, y);
493 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
494 EXPECT_TRUE(FPDFPathSegment_GetClose(segment));
495 // Make sure out of bounds index access fails properly.
496 EXPECT_EQ(nullptr, FPDFPath_GetPathSegment(black_path, 3));
Miklos Vajna12abfd02017-09-15 07:49:03 +0200497
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500498 FPDFPage_InsertObject(page, black_path);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000499 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000500 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000501 CompareBitmap(page_bitmap.get(), 612, 792,
502 "eadc8020a14dfcf091da2688733d8806");
503 }
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500504
505 // Now add a more complex blue path.
506 FPDF_PAGEOBJECT blue_path = FPDFPageObj_CreateNewPath(200, 200);
Lei Zhang3475b482019-05-13 18:30:57 +0000507 EXPECT_TRUE(FPDFPageObj_SetFillColor(blue_path, 0, 0, 255, 255));
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500508 EXPECT_TRUE(FPDFPath_SetDrawMode(blue_path, FPDF_FILLMODE_WINDING, 0));
509 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 230, 230));
510 EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 250, 250, 280, 280, 300, 300));
511 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 325, 325));
512 EXPECT_TRUE(FPDFPath_LineTo(blue_path, 350, 325));
513 EXPECT_TRUE(FPDFPath_BezierTo(blue_path, 375, 330, 390, 360, 400, 400));
514 EXPECT_TRUE(FPDFPath_Close(blue_path));
515 FPDFPage_InsertObject(page, blue_path);
Hui Yingsta929df72021-02-26 23:56:18 +0000516#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
517 static constexpr char kLastChecksum[] = "ed14c60702b1489c597c7d46ece7f86d";
518#else
519 static constexpr char kLastChecksum[] = "9823e1a21bd9b72b6a442ba4f12af946";
520#endif
Lei Zhang107fa7b2018-02-09 21:48:15 +0000521 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000522 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingsta929df72021-02-26 23:56:18 +0000523 CompareBitmap(page_bitmap.get(), 612, 792, kLastChecksum);
Lei Zhang107fa7b2018-02-09 21:48:15 +0000524 }
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500525
526 // Now save the result, closing the page and document
Nicolas Pena207b7272017-05-26 17:37:06 -0400527 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Nicolas Penad03ca422017-03-06 13:54:33 -0500528 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500529 FPDF_ClosePage(page);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500530
531 // Render the saved result
Hui Yingsta929df72021-02-26 23:56:18 +0000532 VerifySavedDocument(612, 792, kLastChecksum);
Nicolas Pena0fc185e2017-02-08 12:13:20 -0500533}
534
Miklos Vajna45501f32019-07-30 07:41:02 +0000535TEST_F(FPDFEditEmbedderTest, ClipPath) {
536 // Load document with a clipped rectangle.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +0000537 ASSERT_TRUE(OpenDocument("clip_path.pdf"));
Miklos Vajna45501f32019-07-30 07:41:02 +0000538 FPDF_PAGE page = LoadPage(0);
539 ASSERT_TRUE(page);
540
541 ASSERT_EQ(1, FPDFPage_CountObjects(page));
542
543 FPDF_PAGEOBJECT triangle = FPDFPage_GetObject(page, 0);
544 ASSERT_TRUE(triangle);
545
546 // Test that we got the expected triangle.
547 ASSERT_EQ(4, FPDFPath_CountSegments(triangle));
548
549 FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(triangle, 0);
550 float x;
551 float y;
552 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
553 EXPECT_EQ(10, x);
554 EXPECT_EQ(10, y);
555 EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
556 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
557
558 segment = FPDFPath_GetPathSegment(triangle, 1);
559 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
560 EXPECT_EQ(25, x);
561 EXPECT_EQ(40, y);
562 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
563 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
564
565 segment = FPDFPath_GetPathSegment(triangle, 2);
566 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
567 EXPECT_EQ(40, x);
568 EXPECT_EQ(10, y);
569 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
570 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
571
572 segment = FPDFPath_GetPathSegment(triangle, 3);
573 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
574 EXPECT_TRUE(FPDFPathSegment_GetClose(segment));
575
576 // Test FPDFPageObj_GetClipPath().
577 ASSERT_EQ(nullptr, FPDFPageObj_GetClipPath(nullptr));
578
579 FPDF_CLIPPATH clip_path = FPDFPageObj_GetClipPath(triangle);
580 ASSERT_TRUE(clip_path);
581
582 // Test FPDFClipPath_CountPaths().
583 ASSERT_EQ(-1, FPDFClipPath_CountPaths(nullptr));
584 ASSERT_EQ(1, FPDFClipPath_CountPaths(clip_path));
585
586 // Test FPDFClipPath_CountPathSegments().
587 ASSERT_EQ(-1, FPDFClipPath_CountPathSegments(nullptr, 0));
588 ASSERT_EQ(-1, FPDFClipPath_CountPathSegments(clip_path, -1));
589 ASSERT_EQ(-1, FPDFClipPath_CountPathSegments(clip_path, 1));
590 ASSERT_EQ(4, FPDFClipPath_CountPathSegments(clip_path, 0));
591
592 // FPDFClipPath_GetPathSegment() negative testing.
593 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(nullptr, 0, 0));
594 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, -1, 0));
595 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, 1, 0));
596 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, 0, -1));
597 ASSERT_EQ(nullptr, FPDFClipPath_GetPathSegment(clip_path, 0, 4));
598
599 // FPDFClipPath_GetPathSegment() positive testing.
600 segment = FPDFClipPath_GetPathSegment(clip_path, 0, 0);
601 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
602 EXPECT_EQ(10, x);
603 EXPECT_EQ(15, y);
604 EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
605 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
606
607 segment = FPDFClipPath_GetPathSegment(clip_path, 0, 1);
608 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
609 EXPECT_EQ(40, x);
610 EXPECT_EQ(15, y);
611 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
612 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
613
614 segment = FPDFClipPath_GetPathSegment(clip_path, 0, 2);
615 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
616 EXPECT_EQ(40, x);
617 EXPECT_EQ(35, y);
618 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
619 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
620
621 segment = FPDFClipPath_GetPathSegment(clip_path, 0, 3);
622 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
623 EXPECT_EQ(10, x);
624 EXPECT_EQ(35, y);
625 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
626 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
627
628 UnloadPage(page);
629}
630
Lei Zhang571f9322019-09-25 12:40:25 +0000631TEST_F(FPDFEditEmbedderTest, BUG_1399) {
632 // Load document with a clipped rectangle.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +0000633 ASSERT_TRUE(OpenDocument("bug_1399.pdf"));
Lei Zhang571f9322019-09-25 12:40:25 +0000634 FPDF_PAGE page = LoadPage(0);
635 ASSERT_TRUE(page);
636
637 ASSERT_EQ(7, FPDFPage_CountObjects(page));
638
639 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 0);
640 ASSERT_TRUE(obj);
641
642 ASSERT_EQ(2, FPDFPath_CountSegments(obj));
643
644 FPDF_PATHSEGMENT segment = FPDFPath_GetPathSegment(obj, 0);
645 float x;
646 float y;
647 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
648 EXPECT_FLOAT_EQ(107.718f, x);
649 EXPECT_FLOAT_EQ(719.922f, y);
650 EXPECT_EQ(FPDF_SEGMENT_MOVETO, FPDFPathSegment_GetType(segment));
651 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
652
653 segment = FPDFPath_GetPathSegment(obj, 1);
654 EXPECT_TRUE(FPDFPathSegment_GetPoint(segment, &x, &y));
655 EXPECT_FLOAT_EQ(394.718f, x);
656 EXPECT_FLOAT_EQ(719.922f, y);
657 EXPECT_EQ(FPDF_SEGMENT_LINETO, FPDFPathSegment_GetType(segment));
658 EXPECT_FALSE(FPDFPathSegment_GetClose(segment));
659
660 FPDF_CLIPPATH clip_path = FPDFPageObj_GetClipPath(obj);
661 ASSERT_TRUE(clip_path);
662
663 EXPECT_EQ(-1, FPDFClipPath_CountPaths(clip_path));
664 EXPECT_EQ(-1, FPDFClipPath_CountPathSegments(clip_path, 0));
665 EXPECT_FALSE(FPDFClipPath_GetPathSegment(clip_path, 0, 0));
666
667 UnloadPage(page);
668}
669
Lei Zhangfcf7e7f2021-07-02 18:46:54 +0000670TEST_F(FPDFEditEmbedderTest, BUG_1549) {
671 static const char kOriginalChecksum[] = "126366fb95e6caf8ea196780075b22b2";
672 static const char kRemovedChecksum[] = "6ec2f27531927882624b37bc7d8e12f4";
673
674 ASSERT_TRUE(OpenDocument("bug_1549.pdf"));
675 FPDF_PAGE page = LoadPage(0);
676
677 {
678 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
679 CompareBitmap(bitmap.get(), 100, 150, kOriginalChecksum);
680
681 ScopedFPDFPageObject obj(FPDFPage_GetObject(page, 0));
682 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj.get()));
683 ASSERT_TRUE(FPDFPage_RemoveObject(page, obj.get()));
684 }
685
686 ASSERT_TRUE(FPDFPage_GenerateContent(page));
687
688 {
689 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
690 CompareBitmap(bitmap.get(), 100, 150, kRemovedChecksum);
691 }
692
693 ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
694 UnloadPage(page);
695
696 // TODO(crbug.com/pdfium/1549): Should be `kRemovedChecksum`.
697 VerifySavedDocument(100, 150, "4f9889cd5993db20f1ab37d677ac8d26");
698}
699
Hui Yingstcb4203d2020-06-09 01:48:47 +0000700TEST_F(FPDFEditEmbedderTest, SetText) {
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000701 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +0000702 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000703 FPDF_PAGE page = LoadPage(0);
704 ASSERT_TRUE(page);
705
706 // Get the "Hello, world!" text object and change it.
707 ASSERT_EQ(2, FPDFPage_CountObjects(page));
708 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
709 ASSERT_TRUE(page_object);
Lei Zhangf0f67682019-04-08 17:03:21 +0000710 ScopedFPDFWideString text1 = GetFPDFWideString(L"Changed for SetText test");
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000711 EXPECT_TRUE(FPDFText_SetText(page_object, text1.get()));
712
713 // Verify the "Hello, world!" text is gone and "Changed for SetText test" is
714 // now displayed.
715 ASSERT_EQ(2, FPDFPage_CountObjects(page));
Hui Yingstcb4203d2020-06-09 01:48:47 +0000716
Hui Yingstbf9eee12022-05-25 21:20:24 +0000717#if BUILDFLAG(IS_APPLE) && !defined(_SKIA_SUPPORT_) && \
718 !defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +0000719 const char kChangedChecksum[] = "b720e83476fd6819d47c533f1f43c728";
Hui Yingstcb4203d2020-06-09 01:48:47 +0000720#else
Tom Andersond4fe5f72021-12-03 20:52:52 +0000721 const char kChangedChecksum[] = "9a85b9354a69c61772ed24151c140f46";
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000722#endif
723 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000724 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstcb4203d2020-06-09 01:48:47 +0000725 CompareBitmap(page_bitmap.get(), 200, 200, kChangedChecksum);
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000726 }
727
728 // Now save the result.
729 EXPECT_TRUE(FPDFPage_GenerateContent(page));
730 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
731
732 UnloadPage(page);
733
734 // Re-open the file and check the changes were kept in the saved .pdf.
Lei Zhang0b494052019-01-31 21:41:15 +0000735 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000736 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +0000737 ASSERT_TRUE(saved_page);
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000738 EXPECT_EQ(2, FPDFPage_CountObjects(saved_page));
739 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000740 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstcb4203d2020-06-09 01:48:47 +0000741 CompareBitmap(page_bitmap.get(), 200, 200, kChangedChecksum);
Henrique Nakashima5ebfd642018-06-07 15:18:55 +0000742 }
743
744 CloseSavedPage(saved_page);
745 CloseSavedDocument();
746}
747
Lei Zhang786544d2021-07-27 21:25:24 +0000748TEST_F(FPDFEditEmbedderTest, SetCharcodesBadParams) {
749 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
750 FPDF_PAGE page = LoadPage(0);
751 ASSERT_TRUE(page);
752
753 ASSERT_EQ(2, FPDFPage_CountObjects(page));
754 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
755 ASSERT_TRUE(page_object);
756
757 const uint32_t kDummyValue = 42;
758 EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, nullptr, 0));
759 EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, nullptr, 1));
760 EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, &kDummyValue, 0));
761 EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, &kDummyValue, 1));
762 EXPECT_FALSE(FPDFText_SetCharcodes(page_object, nullptr, 1));
763
764 UnloadPage(page);
765}
766
Hui Yingst5ce6a3f2020-11-11 02:29:09 +0000767TEST_F(FPDFEditEmbedderTest, SetTextKeepClippingPath) {
Daniel Hosseinianda651442020-07-17 23:30:22 +0000768 // Load document with some text, with parts clipped.
769 ASSERT_TRUE(OpenDocument("bug_1558.pdf"));
770 FPDF_PAGE page = LoadPage(0);
771 ASSERT_TRUE(page);
772
Hui Yingstbf9eee12022-05-25 21:20:24 +0000773#if BUILDFLAG(IS_APPLE) && !defined(_SKIA_SUPPORT_) && \
774 !defined(_SKIA_SUPPORT_PATHS_)
Hui Yingst5ce6a3f2020-11-11 02:29:09 +0000775 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +0000776 "ae7a25c85e0e2dd0c5cb9dd5cd37f6df";
Daniel Hosseinianda651442020-07-17 23:30:22 +0000777#else
Hui Yingst5ce6a3f2020-11-11 02:29:09 +0000778 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +0000779 "7af7fe5b281298261eb66ac2d22f5054";
Daniel Hosseinianda651442020-07-17 23:30:22 +0000780#endif
781 {
782 // When opened before any editing and saving, the clipping path is rendered.
783 ScopedFPDFBitmap original_bitmap = RenderPage(page);
784 CompareBitmap(original_bitmap.get(), 200, 200, kOriginalChecksum);
785 }
786
787 // "Change" the text in the objects to their current values to force them to
788 // regenerate when saving.
789 {
790 ScopedFPDFTextPage text_page(FPDFText_LoadPage(page));
791 ASSERT_TRUE(text_page);
792 const int obj_count = FPDFPage_CountObjects(page);
793 ASSERT_EQ(2, obj_count);
794 for (int i = 0; i < obj_count; ++i) {
795 FPDF_PAGEOBJECT text_obj = FPDFPage_GetObject(page, i);
796 ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_obj));
797 unsigned long size =
798 FPDFTextObj_GetText(text_obj, text_page.get(),
799 /*buffer=*/nullptr, /*length=*/0);
800 ASSERT_GT(size, 0u);
801 std::vector<FPDF_WCHAR> buffer = GetFPDFWideStringBuffer(size);
802 ASSERT_EQ(size, FPDFTextObj_GetText(text_obj, text_page.get(),
803 buffer.data(), size));
804 EXPECT_TRUE(FPDFText_SetText(text_obj, buffer.data()));
805 }
806 }
807
808 {
809 // After editing but before saving, the clipping path is retained.
810 ScopedFPDFBitmap edited_bitmap = RenderPage(page);
811 CompareBitmap(edited_bitmap.get(), 200, 200, kOriginalChecksum);
812 }
813
814 // Save the file.
815 EXPECT_TRUE(FPDFPage_GenerateContent(page));
816 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
817 UnloadPage(page);
818
819 // Open the saved copy and render it.
820 ASSERT_TRUE(OpenSavedDocument());
821 FPDF_PAGE saved_page = LoadSavedPage(0);
822 ASSERT_TRUE(saved_page);
823
824 {
Daniel Hosseinianda651442020-07-17 23:30:22 +0000825 ScopedFPDFBitmap saved_bitmap = RenderSavedPage(saved_page);
Daniel Hosseinian75efd912020-07-21 08:07:28 +0000826 CompareBitmap(saved_bitmap.get(), 200, 200, kOriginalChecksum);
Daniel Hosseinianda651442020-07-17 23:30:22 +0000827 }
828
829 CloseSavedPage(saved_page);
830 CloseSavedDocument();
831}
832
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000833TEST_F(FPDFEditEmbedderTest, BUG_1574) {
834 // Load document with some text within a clipping path.
835 ASSERT_TRUE(OpenDocument("bug_1574.pdf"));
836 FPDF_PAGE page = LoadPage(0);
837 ASSERT_TRUE(page);
838
Hui Yingstbf9eee12022-05-25 21:20:24 +0000839#if BUILDFLAG(IS_APPLE) && !defined(_SKIA_SUPPORT_) && \
840 !defined(_SKIA_SUPPORT_PATHS_)
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000841 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +0000842 "1226bc2b8072622eb28f52321876e814";
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000843#else
844 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +0000845 "c5241eef60b9eac68ed1f2a5fd002703";
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000846#endif
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000847 {
848 // When opened before any editing and saving, the text object is rendered.
849 ScopedFPDFBitmap original_bitmap = RenderPage(page);
850 CompareBitmap(original_bitmap.get(), 200, 300, kOriginalChecksum);
851 }
852
853 // "Change" the text in the objects to their current values to force them to
854 // regenerate when saving.
855 {
856 ScopedFPDFTextPage text_page(FPDFText_LoadPage(page));
857 ASSERT_TRUE(text_page);
858
859 ASSERT_EQ(2, FPDFPage_CountObjects(page));
860 FPDF_PAGEOBJECT text_obj = FPDFPage_GetObject(page, 1);
861 ASSERT_EQ(FPDF_PAGEOBJ_TEXT, FPDFPageObj_GetType(text_obj));
862
863 unsigned long size = FPDFTextObj_GetText(text_obj, text_page.get(),
864 /*buffer=*/nullptr, /*length=*/0);
865 ASSERT_GT(size, 0u);
866 std::vector<FPDF_WCHAR> buffer = GetFPDFWideStringBuffer(size);
867 ASSERT_EQ(size, FPDFTextObj_GetText(text_obj, text_page.get(),
868 buffer.data(), size));
869 EXPECT_TRUE(FPDFText_SetText(text_obj, buffer.data()));
870 }
871
872 // Save the file.
873 EXPECT_TRUE(FPDFPage_GenerateContent(page));
874 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
875 UnloadPage(page);
876
877 // Open the saved copy and render it.
878 ASSERT_TRUE(OpenSavedDocument());
879 FPDF_PAGE saved_page = LoadSavedPage(0);
880 ASSERT_TRUE(saved_page);
881
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000882 {
883 ScopedFPDFBitmap saved_bitmap = RenderSavedPage(saved_page);
Daniel Hosseinian91eeeb92021-01-27 19:53:24 +0000884 CompareBitmap(saved_bitmap.get(), 200, 300, kOriginalChecksum);
Daniel Hosseinian7b819bf2021-01-27 19:40:34 +0000885 }
886
887 CloseSavedPage(saved_page);
888 CloseSavedDocument();
889}
890
Hui Yingst08c40712020-04-29 01:37:35 +0000891TEST_F(FPDFEditEmbedderTest, RemovePageObject) {
Henrique Nakashima35841fa2018-03-15 15:25:16 +0000892 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +0000893 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashima35841fa2018-03-15 15:25:16 +0000894 FPDF_PAGE page = LoadPage(0);
895 ASSERT_TRUE(page);
896
Henrique Nakashimac90adc52018-03-27 16:26:44 +0000897 // Show what the original file looks like.
898 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000899 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +0000900 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Henrique Nakashima35841fa2018-03-15 15:25:16 +0000901 }
902
903 // Get the "Hello, world!" text object and remove it.
904 ASSERT_EQ(2, FPDFPage_CountObjects(page));
905 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
906 ASSERT_TRUE(page_object);
907 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
908
Henrique Nakashimac90adc52018-03-27 16:26:44 +0000909 // Verify the "Hello, world!" text is gone.
910 {
Lei Zhang30ff2532019-01-31 21:37:55 +0000911 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +0000912 CompareBitmap(page_bitmap.get(), 200, 200, kFirstRemovedChecksum);
Henrique Nakashima35841fa2018-03-15 15:25:16 +0000913 }
914 ASSERT_EQ(1, FPDFPage_CountObjects(page));
915
916 UnloadPage(page);
917 FPDFPageObj_Destroy(page_object);
918}
919
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000920void CheckMarkCounts(FPDF_PAGE page,
921 int start_from,
922 int expected_object_count,
923 size_t expected_prime_count,
924 size_t expected_square_count,
925 size_t expected_greater_than_ten_count,
926 size_t expected_bounds_count) {
927 int object_count = FPDFPage_CountObjects(page);
928 ASSERT_EQ(expected_object_count, object_count);
929
930 size_t prime_count = 0;
931 size_t square_count = 0;
932 size_t greater_than_ten_count = 0;
933 size_t bounds_count = 0;
934 for (int i = 0; i < object_count; ++i) {
935 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
936
937 int mark_count = FPDFPageObj_CountMarks(page_object);
938 for (int j = 0; j < mark_count; ++j) {
939 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
940
941 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +0000942 unsigned long name_len = 999u;
943 ASSERT_TRUE(
944 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
945 EXPECT_GT(name_len, 0u);
946 EXPECT_NE(999u, name_len);
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000947 std::wstring name =
948 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
949 if (name == L"Prime") {
950 prime_count++;
951 } else if (name == L"Square") {
952 square_count++;
953 int expected_square = start_from + i;
954 EXPECT_EQ(1, FPDFPageObjMark_CountParams(mark));
955
Henrique Nakashimac3099d12018-09-18 18:08:15 +0000956 unsigned long get_param_key_return = 999u;
957 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer),
958 &get_param_key_return));
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000959 EXPECT_EQ((6u + 1u) * 2u, get_param_key_return);
960 std::wstring key =
961 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
962 EXPECT_EQ(L"Factor", key);
963
964 EXPECT_EQ(FPDF_OBJECT_NUMBER,
Henrique Nakashima94230e52018-07-11 22:02:02 +0000965 FPDFPageObjMark_GetParamValueType(mark, "Factor"));
Henrique Nakashima140dead2018-07-11 21:40:03 +0000966 int square_root;
Henrique Nakashima94230e52018-07-11 22:02:02 +0000967 EXPECT_TRUE(
968 FPDFPageObjMark_GetParamIntValue(mark, "Factor", &square_root));
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000969 EXPECT_EQ(expected_square, square_root * square_root);
970 } else if (name == L"GreaterThanTen") {
971 greater_than_ten_count++;
972 } else if (name == L"Bounds") {
973 bounds_count++;
974 EXPECT_EQ(1, FPDFPageObjMark_CountParams(mark));
975
Henrique Nakashimac3099d12018-09-18 18:08:15 +0000976 unsigned long get_param_key_return = 999u;
977 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer),
978 &get_param_key_return));
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000979 EXPECT_EQ((8u + 1u) * 2u, get_param_key_return);
980 std::wstring key =
981 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
982 EXPECT_EQ(L"Position", key);
983
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000984 EXPECT_EQ(FPDF_OBJECT_STRING,
Henrique Nakashima94230e52018-07-11 22:02:02 +0000985 FPDFPageObjMark_GetParamValueType(mark, "Position"));
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000986 unsigned long length;
Henrique Nakashimaa3406772018-07-13 19:10:53 +0000987 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
988 mark, "Position", buffer, sizeof(buffer), &length));
Henrique Nakashimacbed9492018-07-10 21:54:26 +0000989 ASSERT_GT(length, 0u);
Henrique Nakashima140dead2018-07-11 21:40:03 +0000990 std::wstring value =
991 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
Henrique Nakashimad8df8c32018-07-12 22:15:09 +0000992
Henrique Nakashimaa3406772018-07-13 19:10:53 +0000993 // "Position" can be "First", "Last", or "End".
Henrique Nakashimad8df8c32018-07-12 22:15:09 +0000994 if (i == 0) {
995 EXPECT_EQ((5u + 1u) * 2u, length);
996 EXPECT_EQ(L"First", value);
997 } else if (i == object_count - 1) {
Henrique Nakashimaa3406772018-07-13 19:10:53 +0000998 if (length == (4u + 1u) * 2u) {
999 EXPECT_EQ(L"Last", value);
1000 } else if (length == (3u + 1u) * 2u) {
1001 EXPECT_EQ(L"End", value);
1002 } else {
1003 FAIL();
1004 }
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00001005 } else {
1006 FAIL();
1007 }
Henrique Nakashimacbed9492018-07-10 21:54:26 +00001008 } else {
1009 FAIL();
1010 }
1011 }
1012 }
1013
1014 // Expect certain number of tagged objects. The test file contains strings
1015 // from 1 to 19.
1016 EXPECT_EQ(expected_prime_count, prime_count);
1017 EXPECT_EQ(expected_square_count, square_count);
1018 EXPECT_EQ(expected_greater_than_ten_count, greater_than_ten_count);
1019 EXPECT_EQ(expected_bounds_count, bounds_count);
1020}
1021
Lei Zhangab41f252018-12-23 03:10:50 +00001022TEST_F(FPDFEditEmbedderTest, ReadMarkedObjectsIndirectDict) {
Henrique Nakashimacbed9492018-07-10 21:54:26 +00001023 // Load document with some text marked with an indirect property.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001024 ASSERT_TRUE(OpenDocument("text_in_page_marked_indirect.pdf"));
Henrique Nakashimacbed9492018-07-10 21:54:26 +00001025 FPDF_PAGE page = LoadPage(0);
1026 ASSERT_TRUE(page);
1027
1028 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
1029
1030 UnloadPage(page);
1031}
1032
Hui Yingstf26b5f82020-11-17 05:26:03 +00001033TEST_F(FPDFEditEmbedderTest, RemoveMarkedObjectsPrime) {
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001034 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001035 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001036 FPDF_PAGE page = LoadPage(0);
1037 ASSERT_TRUE(page);
1038
1039 // Show what the original file looks like.
1040 {
Hui Yingstbf9eee12022-05-25 21:20:24 +00001041#if defined(_SKIA_SUPPORT_)
Hui Yingstf26b5f82020-11-17 05:26:03 +00001042 static constexpr char kOriginalChecksum[] =
Hui Yingstbf9eee12022-05-25 21:20:24 +00001043 "34ac4e0f3ba510760be09d0e19c1b43e";
1044#elif BUILDFLAG(IS_APPLE) && !defined(_SKIA_SUPPORT_PATHS_)
Hui Yingstf26b5f82020-11-17 05:26:03 +00001045 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001046 "966579fb98206858ce2f0a1f94a74d05";
Hui Yingstf26b5f82020-11-17 05:26:03 +00001047#else
1048 static constexpr char kOriginalChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001049 "3d5a3de53d5866044c2b6bf339742c97";
1050#endif
Lei Zhang30ff2532019-01-31 21:37:55 +00001051 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstf26b5f82020-11-17 05:26:03 +00001052 CompareBitmap(page_bitmap.get(), 200, 200, kOriginalChecksum);
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001053 }
1054
Henrique Nakashimacbed9492018-07-10 21:54:26 +00001055 constexpr int expected_object_count = 19;
1056 CheckMarkCounts(page, 1, expected_object_count, 8, 4, 9, 1);
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001057
Henrique Nakashimacbed9492018-07-10 21:54:26 +00001058 // Get all objects marked with "Prime"
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001059 std::vector<FPDF_PAGEOBJECT> primes;
Henrique Nakashimacbed9492018-07-10 21:54:26 +00001060 for (int i = 0; i < expected_object_count; ++i) {
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001061 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1062
1063 int mark_count = FPDFPageObj_CountMarks(page_object);
1064 for (int j = 0; j < mark_count; ++j) {
1065 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1066
1067 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +00001068 unsigned long name_len = 999u;
1069 ASSERT_TRUE(
1070 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1071 EXPECT_GT(name_len, 0u);
1072 EXPECT_NE(999u, name_len);
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001073 std::wstring name =
1074 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1075 if (name == L"Prime") {
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001076 primes.push_back(page_object);
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001077 }
1078 }
1079 }
1080
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001081 // Remove all objects marked with "Prime".
1082 for (FPDF_PAGEOBJECT page_object : primes) {
1083 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1084 FPDFPageObj_Destroy(page_object);
1085 }
1086
1087 EXPECT_EQ(11, FPDFPage_CountObjects(page));
Hui Yingstbf9eee12022-05-25 21:20:24 +00001088#if defined(_SKIA_SUPPORT_)
Hui Yingstf26b5f82020-11-17 05:26:03 +00001089 static constexpr char kNonPrimesChecksum[] =
Hui Yingstbf9eee12022-05-25 21:20:24 +00001090 "c671fa07b63e85c4201b9926e880fda8";
Hui Yingstf26b5f82020-11-17 05:26:03 +00001091 static constexpr char kNonPrimesAfterSaveChecksum[] =
Hui Yingstbf9eee12022-05-25 21:20:24 +00001092 "c671fa07b63e85c4201b9926e880fda8";
1093#elif BUILDFLAG(IS_APPLE) && !defined(_SKIA_SUPPORT_PATHS_)
Hui Yingstf26b5f82020-11-17 05:26:03 +00001094 static constexpr char kNonPrimesChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001095 "6e19a4dd674b522cd39cf41956559bd6";
Hui Yingstf26b5f82020-11-17 05:26:03 +00001096 static constexpr char kNonPrimesAfterSaveChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001097 "3cb35c681f8fb5a43a49146ac7caa818";
Hui Yingstf26b5f82020-11-17 05:26:03 +00001098#else
1099 static constexpr char kNonPrimesChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001100 "bc8623c052f12376c3d8dd09a6cd27df";
Hui Yingstf26b5f82020-11-17 05:26:03 +00001101 static constexpr char kNonPrimesAfterSaveChecksum[] =
Tom Andersond4fe5f72021-12-03 20:52:52 +00001102 "bc8623c052f12376c3d8dd09a6cd27df";
1103#endif
Henrique Nakashimaa5078b72018-09-10 17:09:42 +00001104 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001105 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstf26b5f82020-11-17 05:26:03 +00001106 CompareBitmap(page_bitmap.get(), 200, 200, kNonPrimesChecksum);
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001107 }
1108
Henrique Nakashimaa5078b72018-09-10 17:09:42 +00001109 // Save the file.
1110 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1111 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001112 UnloadPage(page);
Henrique Nakashimaa5078b72018-09-10 17:09:42 +00001113
1114 // Re-open the file and check the prime marks are not there anymore.
Lei Zhang0b494052019-01-31 21:41:15 +00001115 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimaa5078b72018-09-10 17:09:42 +00001116 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001117 ASSERT_TRUE(saved_page);
Henrique Nakashimaa5078b72018-09-10 17:09:42 +00001118 EXPECT_EQ(11, FPDFPage_CountObjects(saved_page));
1119
1120 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001121 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstf26b5f82020-11-17 05:26:03 +00001122 CompareBitmap(page_bitmap.get(), 200, 200, kNonPrimesAfterSaveChecksum);
Henrique Nakashimaa5078b72018-09-10 17:09:42 +00001123 }
1124
1125 CloseSavedPage(saved_page);
1126 CloseSavedDocument();
Henrique Nakashimac90adc52018-03-27 16:26:44 +00001127}
1128
Lei Zhangab41f252018-12-23 03:10:50 +00001129TEST_F(FPDFEditEmbedderTest, RemoveMarks) {
Henrique Nakashimafed4adb2018-07-13 19:47:22 +00001130 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001131 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimafed4adb2018-07-13 19:47:22 +00001132 FPDF_PAGE page = LoadPage(0);
1133 ASSERT_TRUE(page);
1134
1135 constexpr int kExpectedObjectCount = 19;
1136 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
1137
1138 // Remove all "Prime" content marks.
1139 for (int i = 0; i < kExpectedObjectCount; ++i) {
1140 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1141
1142 int mark_count = FPDFPageObj_CountMarks(page_object);
1143 for (int j = mark_count - 1; j >= 0; --j) {
1144 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1145
1146 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +00001147 unsigned long name_len = 999u;
1148 ASSERT_TRUE(
1149 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1150 EXPECT_GT(name_len, 0u);
1151 EXPECT_NE(999u, name_len);
Henrique Nakashimafed4adb2018-07-13 19:47:22 +00001152 std::wstring name =
1153 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1154 if (name == L"Prime") {
1155 // Remove mark.
1156 EXPECT_TRUE(FPDFPageObj_RemoveMark(page_object, mark));
1157
1158 // Verify there is now one fewer mark in the page object.
1159 EXPECT_EQ(mark_count - 1, FPDFPageObj_CountMarks(page_object));
1160 }
1161 }
1162 }
1163
1164 // Verify there are 0 "Prime" content marks now.
1165 CheckMarkCounts(page, 1, kExpectedObjectCount, 0, 4, 9, 1);
1166
1167 // Save the file.
1168 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1169 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1170 UnloadPage(page);
1171
1172 // Re-open the file and check the prime marks are not there anymore.
Lei Zhang0b494052019-01-31 21:41:15 +00001173 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimafed4adb2018-07-13 19:47:22 +00001174 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001175 ASSERT_TRUE(saved_page);
Henrique Nakashimafed4adb2018-07-13 19:47:22 +00001176
1177 CheckMarkCounts(saved_page, 1, kExpectedObjectCount, 0, 4, 9, 1);
1178
1179 CloseSavedPage(saved_page);
1180 CloseSavedDocument();
1181}
1182
Lei Zhangab41f252018-12-23 03:10:50 +00001183TEST_F(FPDFEditEmbedderTest, RemoveMarkParam) {
Henrique Nakashimacf403ba2018-07-13 20:12:41 +00001184 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001185 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimacf403ba2018-07-13 20:12:41 +00001186 FPDF_PAGE page = LoadPage(0);
1187 ASSERT_TRUE(page);
1188
1189 constexpr int kExpectedObjectCount = 19;
1190 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
1191
1192 // Remove all "Square" content marks parameters.
1193 for (int i = 0; i < kExpectedObjectCount; ++i) {
1194 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1195
1196 int mark_count = FPDFPageObj_CountMarks(page_object);
1197 for (int j = 0; j < mark_count; ++j) {
1198 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1199
1200 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +00001201 unsigned long name_len = 999u;
1202 ASSERT_TRUE(
1203 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1204 EXPECT_GT(name_len, 0u);
1205 EXPECT_NE(999u, name_len);
Henrique Nakashimacf403ba2018-07-13 20:12:41 +00001206 std::wstring name =
1207 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1208 if (name == L"Square") {
1209 // Show the mark has a "Factor" parameter.
1210 int out_value;
1211 EXPECT_TRUE(
1212 FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
1213
1214 // Remove parameter.
1215 EXPECT_TRUE(FPDFPageObjMark_RemoveParam(page_object, mark, "Factor"));
1216
1217 // Verify the "Factor" parameter is gone.
1218 EXPECT_FALSE(
1219 FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
1220 }
1221 }
1222 }
1223
1224 // Save the file.
1225 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1226 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1227 UnloadPage(page);
1228
1229 // Re-open the file and check the "Factor" parameters are still gone.
Lei Zhang0b494052019-01-31 21:41:15 +00001230 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimacf403ba2018-07-13 20:12:41 +00001231 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001232 ASSERT_TRUE(saved_page);
Henrique Nakashimacf403ba2018-07-13 20:12:41 +00001233
1234 size_t square_count = 0;
1235 for (int i = 0; i < kExpectedObjectCount; ++i) {
1236 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(saved_page, i);
1237
1238 int mark_count = FPDFPageObj_CountMarks(page_object);
1239 for (int j = 0; j < mark_count; ++j) {
1240 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, j);
1241
1242 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +00001243 unsigned long name_len = 999u;
1244 ASSERT_TRUE(
1245 FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
1246 EXPECT_GT(name_len, 0u);
1247 EXPECT_NE(999u, name_len);
Henrique Nakashimacf403ba2018-07-13 20:12:41 +00001248 std::wstring name =
1249 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
1250 if (name == L"Square") {
1251 // Verify the "Factor" parameter is still gone.
1252 int out_value;
1253 EXPECT_FALSE(
1254 FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
1255
1256 ++square_count;
1257 }
1258 }
1259 }
1260
1261 // Verify the parameters are gone, but the marks are not.
1262 EXPECT_EQ(4u, square_count);
1263
1264 CloseSavedPage(saved_page);
1265 CloseSavedDocument();
1266}
1267
Lei Zhangab41f252018-12-23 03:10:50 +00001268TEST_F(FPDFEditEmbedderTest, MaintainMarkedObjects) {
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001269 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001270 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001271 FPDF_PAGE page = LoadPage(0);
1272 ASSERT_TRUE(page);
1273
1274 // Iterate over all objects, counting the number of times each content mark
1275 // name appears.
1276 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
1277
1278 // Remove first page object.
1279 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1280 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1281 FPDFPageObj_Destroy(page_object);
1282
1283 CheckMarkCounts(page, 2, 18, 8, 3, 9, 1);
1284
1285 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1286 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1287
1288 UnloadPage(page);
1289
Lei Zhang0b494052019-01-31 21:41:15 +00001290 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001291 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001292 ASSERT_TRUE(saved_page);
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001293
1294 CheckMarkCounts(saved_page, 2, 18, 8, 3, 9, 1);
1295
1296 CloseSavedPage(saved_page);
1297 CloseSavedDocument();
1298}
1299
Lei Zhangab41f252018-12-23 03:10:50 +00001300TEST_F(FPDFEditEmbedderTest, MaintainIndirectMarkedObjects) {
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001301 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001302 ASSERT_TRUE(OpenDocument("text_in_page_marked_indirect.pdf"));
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001303 FPDF_PAGE page = LoadPage(0);
1304 ASSERT_TRUE(page);
1305
1306 // Iterate over all objects, counting the number of times each content mark
1307 // name appears.
1308 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
1309
1310 // Remove first page object.
1311 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1312 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1313 FPDFPageObj_Destroy(page_object);
1314
1315 CheckMarkCounts(page, 2, 18, 8, 3, 9, 1);
1316
1317 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1318 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1319
1320 UnloadPage(page);
1321
Lei Zhang0b494052019-01-31 21:41:15 +00001322 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001323 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001324 ASSERT_TRUE(saved_page);
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00001325
1326 CheckMarkCounts(saved_page, 2, 18, 8, 3, 9, 1);
1327
1328 CloseSavedPage(saved_page);
1329 CloseSavedDocument();
1330}
1331
Lei Zhangab41f252018-12-23 03:10:50 +00001332TEST_F(FPDFEditEmbedderTest, RemoveExistingPageObject) {
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001333 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001334 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001335 FPDF_PAGE page = LoadPage(0);
1336 ASSERT_TRUE(page);
1337
1338 // Get the "Hello, world!" text object and remove it.
1339 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1340 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1341 ASSERT_TRUE(page_object);
1342 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1343
1344 // Verify the "Hello, world!" text is gone.
1345 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1346
1347 // Save the file
1348 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1349 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1350 UnloadPage(page);
1351 FPDFPageObj_Destroy(page_object);
1352
1353 // Re-open the file and check the page object count is still 1.
Lei Zhang0b494052019-01-31 21:41:15 +00001354 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001355 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001356 ASSERT_TRUE(saved_page);
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001357 EXPECT_EQ(1, FPDFPage_CountObjects(saved_page));
1358 CloseSavedPage(saved_page);
1359 CloseSavedDocument();
1360}
1361
Hui Yingstcb4203d2020-06-09 01:48:47 +00001362TEST_F(FPDFEditEmbedderTest, RemoveExistingPageObjectSplitStreamsNotLonely) {
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001363 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001364 ASSERT_TRUE(OpenDocument("hello_world_split_streams.pdf"));
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001365 FPDF_PAGE page = LoadPage(0);
1366 ASSERT_TRUE(page);
1367
1368 // Get the "Hello, world!" text object and remove it. There is another object
1369 // in the same stream that says "Goodbye, world!"
1370 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1371 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1372 ASSERT_TRUE(page_object);
1373 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1374
1375 // Verify the "Hello, world!" text is gone.
1376 ASSERT_EQ(2, FPDFPage_CountObjects(page));
Hui Yingstbf9eee12022-05-25 21:20:24 +00001377#if BUILDFLAG(IS_APPLE) && !defined(_SKIA_SUPPORT_) && \
1378 !defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +00001379 const char kHelloRemovedChecksum[] = "5508c2f06d104050f74f655693e38c2c";
Hui Yingstcb4203d2020-06-09 01:48:47 +00001380#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00001381 const char kHelloRemovedChecksum[] = "a8cd82499cf744e0862ca468c9d4ceb8";
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001382#endif
1383 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001384 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstcb4203d2020-06-09 01:48:47 +00001385 CompareBitmap(page_bitmap.get(), 200, 200, kHelloRemovedChecksum);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001386 }
1387
1388 // Save the file
1389 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1390 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1391 UnloadPage(page);
1392 FPDFPageObj_Destroy(page_object);
1393
1394 // Re-open the file and check the page object count is still 2.
Lei Zhang0b494052019-01-31 21:41:15 +00001395 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001396 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001397 ASSERT_TRUE(saved_page);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001398
1399 EXPECT_EQ(2, FPDFPage_CountObjects(saved_page));
1400 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001401 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstcb4203d2020-06-09 01:48:47 +00001402 CompareBitmap(page_bitmap.get(), 200, 200, kHelloRemovedChecksum);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001403 }
1404
1405 CloseSavedPage(saved_page);
1406 CloseSavedDocument();
1407}
1408
Hui Yingst08c40712020-04-29 01:37:35 +00001409TEST_F(FPDFEditEmbedderTest, RemoveExistingPageObjectSplitStreamsLonely) {
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001410 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001411 ASSERT_TRUE(OpenDocument("hello_world_split_streams.pdf"));
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001412 FPDF_PAGE page = LoadPage(0);
1413 ASSERT_TRUE(page);
1414
1415 // Get the "Greetings, world!" text object and remove it. This is the only
1416 // object in the stream.
1417 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1418 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 2);
1419 ASSERT_TRUE(page_object);
1420 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1421
1422 // Verify the "Greetings, world!" text is gone.
1423 ASSERT_EQ(2, FPDFPage_CountObjects(page));
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001424 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001425 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001426 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001427 }
1428
1429 // Save the file
1430 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1431 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1432 UnloadPage(page);
1433 FPDFPageObj_Destroy(page_object);
1434
1435 // Re-open the file and check the page object count is still 2.
Lei Zhang0b494052019-01-31 21:41:15 +00001436 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001437 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001438 ASSERT_TRUE(saved_page);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001439
1440 EXPECT_EQ(2, FPDFPage_CountObjects(saved_page));
1441 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001442 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001443 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001444 }
1445
1446 CloseSavedPage(saved_page);
1447 CloseSavedDocument();
1448}
1449
Lei Zhangab41f252018-12-23 03:10:50 +00001450TEST_F(FPDFEditEmbedderTest, GetContentStream) {
Henrique Nakashima6eb79392018-06-12 20:27:35 +00001451 // Load document with some text split across streams.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001452 ASSERT_TRUE(OpenDocument("split_streams.pdf"));
Henrique Nakashima6eb79392018-06-12 20:27:35 +00001453 FPDF_PAGE page = LoadPage(0);
1454 ASSERT_TRUE(page);
1455
1456 // Content stream 0: page objects 0-14.
1457 // Content stream 1: page objects 15-17.
1458 // Content stream 2: page object 18.
1459 ASSERT_EQ(19, FPDFPage_CountObjects(page));
1460 for (int i = 0; i < 19; i++) {
1461 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1462 ASSERT_TRUE(page_object);
1463 CPDF_PageObject* cpdf_page_object =
1464 CPDFPageObjectFromFPDFPageObject(page_object);
1465 if (i < 15)
1466 EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1467 else if (i < 18)
1468 EXPECT_EQ(1, cpdf_page_object->GetContentStream()) << i;
1469 else
1470 EXPECT_EQ(2, cpdf_page_object->GetContentStream()) << i;
1471 }
1472
1473 UnloadPage(page);
1474}
1475
Hui Yingst0d692fe2020-11-06 17:32:50 +00001476TEST_F(FPDFEditEmbedderTest, RemoveAllFromStream) {
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001477 // Load document with some text split across streams.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001478 ASSERT_TRUE(OpenDocument("split_streams.pdf"));
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001479 FPDF_PAGE page = LoadPage(0);
1480 ASSERT_TRUE(page);
1481
1482 // Content stream 0: page objects 0-14.
1483 // Content stream 1: page objects 15-17.
1484 // Content stream 2: page object 18.
1485 ASSERT_EQ(19, FPDFPage_CountObjects(page));
1486
1487 // Loop backwards because objects will being removed, which shifts the indexes
1488 // after the removed position.
1489 for (int i = 18; i >= 0; i--) {
1490 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1491 ASSERT_TRUE(page_object);
1492 CPDF_PageObject* cpdf_page_object =
1493 CPDFPageObjectFromFPDFPageObject(page_object);
1494
1495 // Empty content stream 1.
1496 if (cpdf_page_object->GetContentStream() == 1) {
1497 EXPECT_TRUE(FPDFPage_RemoveObject(page, page_object));
1498 FPDFPageObj_Destroy(page_object);
1499 }
1500 }
1501
1502 // Content stream 0: page objects 0-14.
1503 // Content stream 2: page object 15.
1504 ASSERT_EQ(16, FPDFPage_CountObjects(page));
1505 for (int i = 0; i < 16; i++) {
1506 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1507 ASSERT_TRUE(page_object);
1508 CPDF_PageObject* cpdf_page_object =
1509 CPDFPageObjectFromFPDFPageObject(page_object);
1510 if (i < 15)
1511 EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1512 else
1513 EXPECT_EQ(2, cpdf_page_object->GetContentStream()) << i;
1514 }
1515
1516 // Generate contents should remove the empty stream and update the page
1517 // objects' contents stream indexes.
1518 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1519
1520 // Content stream 0: page objects 0-14.
1521 // Content stream 1: page object 15.
1522 ASSERT_EQ(16, FPDFPage_CountObjects(page));
1523 for (int i = 0; i < 16; i++) {
1524 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1525 ASSERT_TRUE(page_object);
1526 CPDF_PageObject* cpdf_page_object =
1527 CPDFPageObjectFromFPDFPageObject(page_object);
1528 if (i < 15)
1529 EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1530 else
1531 EXPECT_EQ(1, cpdf_page_object->GetContentStream()) << i;
1532 }
1533
Hui Yingstbf9eee12022-05-25 21:20:24 +00001534#if defined(_SKIA_SUPPORT_)
1535 const char kStream1RemovedChecksum[] = "b9bb0acfdba4bb5d2e578e7b73341baf";
1536#elif BUILDFLAG(IS_APPLE) && !defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +00001537 const char kStream1RemovedChecksum[] = "3cdc75af44c15bed80998facd6e674c9";
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001538#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00001539 const char kStream1RemovedChecksum[] = "b474826df1acedb05c7b82e1e49e64a6";
1540#endif
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001541 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001542 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst0d692fe2020-11-06 17:32:50 +00001543 CompareBitmap(page_bitmap.get(), 200, 200, kStream1RemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001544 }
1545
1546 // Save the file
1547 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1548 UnloadPage(page);
1549
1550 // Re-open the file and check the page object count is still 16, and that
1551 // content stream 1 was removed.
Lei Zhang0b494052019-01-31 21:41:15 +00001552 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001553 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001554 ASSERT_TRUE(saved_page);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001555
1556 // Content stream 0: page objects 0-14.
1557 // Content stream 1: page object 15.
1558 EXPECT_EQ(16, FPDFPage_CountObjects(saved_page));
1559 for (int i = 0; i < 16; i++) {
1560 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(saved_page, i);
1561 ASSERT_TRUE(page_object);
1562 CPDF_PageObject* cpdf_page_object =
1563 CPDFPageObjectFromFPDFPageObject(page_object);
1564 if (i < 15)
1565 EXPECT_EQ(0, cpdf_page_object->GetContentStream()) << i;
1566 else
1567 EXPECT_EQ(1, cpdf_page_object->GetContentStream()) << i;
1568 }
1569
1570 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001571 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingst0d692fe2020-11-06 17:32:50 +00001572 CompareBitmap(page_bitmap.get(), 200, 200, kStream1RemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001573 }
1574
1575 CloseSavedPage(saved_page);
1576 CloseSavedDocument();
1577}
1578
Lei Zhangab41f252018-12-23 03:10:50 +00001579TEST_F(FPDFEditEmbedderTest, RemoveAllFromSingleStream) {
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001580 // Load document with a single stream.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001581 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001582 FPDF_PAGE page = LoadPage(0);
1583 ASSERT_TRUE(page);
1584
1585 // Content stream 0: page objects 0-1.
1586 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1587
1588 // Loop backwards because objects will being removed, which shifts the indexes
1589 // after the removed position.
1590 for (int i = 1; i >= 0; i--) {
1591 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1592 ASSERT_TRUE(page_object);
1593 CPDF_PageObject* cpdf_page_object =
1594 CPDFPageObjectFromFPDFPageObject(page_object);
1595 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1596 ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
1597 FPDFPageObj_Destroy(page_object);
1598 }
1599
1600 // No more objects in the stream
1601 ASSERT_EQ(0, FPDFPage_CountObjects(page));
1602
1603 // Generate contents should remove the empty stream and update the page
1604 // objects' contents stream indexes.
1605 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1606
1607 ASSERT_EQ(0, FPDFPage_CountObjects(page));
1608
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001609 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001610 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst3b6136a2020-06-09 00:39:33 +00001611 CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001612 }
1613
1614 // Save the file
1615 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1616 UnloadPage(page);
1617
1618 // Re-open the file and check the page object count is still 0.
Lei Zhang0b494052019-01-31 21:41:15 +00001619 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001620 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001621 ASSERT_TRUE(saved_page);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001622
1623 EXPECT_EQ(0, FPDFPage_CountObjects(saved_page));
1624 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001625 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingst3b6136a2020-06-09 00:39:33 +00001626 CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001627 }
1628
1629 CloseSavedPage(saved_page);
1630 CloseSavedDocument();
1631}
1632
Hui Yingst08c40712020-04-29 01:37:35 +00001633TEST_F(FPDFEditEmbedderTest, RemoveFirstFromSingleStream) {
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001634 // Load document with a single stream.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001635 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001636 FPDF_PAGE page = LoadPage(0);
1637 ASSERT_TRUE(page);
1638
1639 // Content stream 0: page objects 0-1.
1640 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1641
1642 // Remove first object.
1643 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
1644 ASSERT_TRUE(page_object);
1645 CPDF_PageObject* cpdf_page_object =
1646 CPDFPageObjectFromFPDFPageObject(page_object);
1647 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1648 ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
1649 FPDFPageObj_Destroy(page_object);
1650
1651 // One object left in the stream.
1652 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1653 page_object = FPDFPage_GetObject(page, 0);
1654 ASSERT_TRUE(page_object);
1655 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1656 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1657
1658 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1659
1660 // Still one object left in the stream.
1661 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1662 page_object = FPDFPage_GetObject(page, 0);
1663 ASSERT_TRUE(page_object);
1664 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1665 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1666
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001667 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001668 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001669 CompareBitmap(page_bitmap.get(), 200, 200, kFirstRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001670 }
1671
1672 // Save the file
1673 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1674 UnloadPage(page);
1675
1676 // Re-open the file and check the page object count is still 0.
Lei Zhang0b494052019-01-31 21:41:15 +00001677 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001678 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001679 ASSERT_TRUE(saved_page);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001680
1681 ASSERT_EQ(1, FPDFPage_CountObjects(saved_page));
1682 page_object = FPDFPage_GetObject(saved_page, 0);
1683 ASSERT_TRUE(page_object);
1684 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1685 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1686 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001687 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001688 CompareBitmap(page_bitmap.get(), 200, 200, kFirstRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001689 }
1690
1691 CloseSavedPage(saved_page);
1692 CloseSavedDocument();
1693}
1694
Hui Yingst08c40712020-04-29 01:37:35 +00001695TEST_F(FPDFEditEmbedderTest, RemoveLastFromSingleStream) {
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001696 // Load document with a single stream.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001697 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001698 FPDF_PAGE page = LoadPage(0);
1699 ASSERT_TRUE(page);
1700
1701 // Content stream 0: page objects 0-1.
1702 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1703
1704 // Remove last object
1705 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 1);
1706 ASSERT_TRUE(page_object);
1707 CPDF_PageObject* cpdf_page_object =
1708 CPDFPageObjectFromFPDFPageObject(page_object);
1709 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1710 ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
1711 FPDFPageObj_Destroy(page_object);
1712
1713 // One object left in the stream.
1714 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1715 page_object = FPDFPage_GetObject(page, 0);
1716 ASSERT_TRUE(page_object);
1717 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1718 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1719
1720 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1721
1722 // Still one object left in the stream.
1723 ASSERT_EQ(1, FPDFPage_CountObjects(page));
1724 page_object = FPDFPage_GetObject(page, 0);
1725 ASSERT_TRUE(page_object);
1726 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1727 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1728
Hui Yingstb4baceb2020-04-28 23:46:10 +00001729 using pdfium::kHelloWorldRemovedChecksum;
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001730 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001731 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001732 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001733 }
1734
1735 // Save the file
1736 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1737 UnloadPage(page);
1738
1739 // Re-open the file and check the page object count is still 0.
Lei Zhang0b494052019-01-31 21:41:15 +00001740 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001741 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001742 ASSERT_TRUE(saved_page);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001743
1744 ASSERT_EQ(1, FPDFPage_CountObjects(saved_page));
1745 page_object = FPDFPage_GetObject(saved_page, 0);
1746 ASSERT_TRUE(page_object);
1747 cpdf_page_object = CPDFPageObjectFromFPDFPageObject(page_object);
1748 ASSERT_EQ(0, cpdf_page_object->GetContentStream());
1749 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001750 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001751 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001752 }
1753
1754 CloseSavedPage(saved_page);
1755 CloseSavedDocument();
1756}
1757
Lei Zhangab41f252018-12-23 03:10:50 +00001758TEST_F(FPDFEditEmbedderTest, RemoveAllFromMultipleStreams) {
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001759 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001760 ASSERT_TRUE(OpenDocument("hello_world_split_streams.pdf"));
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001761 FPDF_PAGE page = LoadPage(0);
1762 ASSERT_TRUE(page);
1763
1764 // Content stream 0: page objects 0-1.
1765 // Content stream 1: page object 2.
1766 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1767
1768 // Loop backwards because objects will being removed, which shifts the indexes
1769 // after the removed position.
1770 for (int i = 2; i >= 0; i--) {
1771 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, i);
1772 ASSERT_TRUE(page_object);
1773 ASSERT_TRUE(FPDFPage_RemoveObject(page, page_object));
1774 FPDFPageObj_Destroy(page_object);
1775 }
1776
1777 // No more objects in the page.
1778 ASSERT_EQ(0, FPDFPage_CountObjects(page));
1779
1780 // Generate contents should remove the empty streams and update the page
1781 // objects' contents stream indexes.
1782 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1783
1784 ASSERT_EQ(0, FPDFPage_CountObjects(page));
1785
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001786 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001787 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst3b6136a2020-06-09 00:39:33 +00001788 CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001789 }
1790
1791 // Save the file
1792 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1793 UnloadPage(page);
1794
1795 // Re-open the file and check the page object count is still 0.
Lei Zhang0b494052019-01-31 21:41:15 +00001796 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001797 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001798 ASSERT_TRUE(saved_page);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001799
1800 EXPECT_EQ(0, FPDFPage_CountObjects(saved_page));
1801 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001802 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingst3b6136a2020-06-09 00:39:33 +00001803 CompareBitmap(page_bitmap.get(), 200, 200, kAllRemovedChecksum);
Henrique Nakashima0dcf1f42018-06-21 18:51:15 +00001804 }
1805
1806 CloseSavedPage(saved_page);
1807 CloseSavedDocument();
1808}
1809
Lei Zhangab41f252018-12-23 03:10:50 +00001810TEST_F(FPDFEditEmbedderTest, InsertPageObjectAndSave) {
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001811 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001812 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001813 FPDF_PAGE page = LoadPage(0);
1814 ASSERT_TRUE(page);
1815
1816 // Add a red rectangle.
1817 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1818 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00001819 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001820 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
1821 FPDFPage_InsertObject(page, red_rect);
1822
1823 // Verify the red rectangle was added.
1824 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1825
1826 // Save the file
1827 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1828 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1829 UnloadPage(page);
1830
1831 // Re-open the file and check the page object count is still 3.
Lei Zhang0b494052019-01-31 21:41:15 +00001832 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001833 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001834 ASSERT_TRUE(saved_page);
Henrique Nakashimac49e62e2018-04-16 20:58:47 +00001835 EXPECT_EQ(3, FPDFPage_CountObjects(saved_page));
1836 CloseSavedPage(saved_page);
1837 CloseSavedDocument();
1838}
1839
Lei Zhangab41f252018-12-23 03:10:50 +00001840TEST_F(FPDFEditEmbedderTest, InsertPageObjectEditAndSave) {
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001841 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001842 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001843 FPDF_PAGE page = LoadPage(0);
1844 ASSERT_TRUE(page);
1845
1846 // Add a red rectangle.
1847 ASSERT_EQ(2, FPDFPage_CountObjects(page));
1848 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00001849 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 100, 100, 255));
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001850 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
1851 FPDFPage_InsertObject(page, red_rect);
1852
1853 // Verify the red rectangle was added.
1854 ASSERT_EQ(3, FPDFPage_CountObjects(page));
1855
1856 // Generate content but change it again
1857 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Lei Zhang3475b482019-05-13 18:30:57 +00001858 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001859
1860 // Save the file
1861 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1862 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1863 UnloadPage(page);
1864
1865 // Re-open the file and check the page object count is still 3.
Lei Zhang0b494052019-01-31 21:41:15 +00001866 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001867 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001868 ASSERT_TRUE(saved_page);
Henrique Nakashima27cf78d2018-06-14 16:22:30 +00001869 EXPECT_EQ(3, FPDFPage_CountObjects(saved_page));
1870 CloseSavedPage(saved_page);
1871 CloseSavedDocument();
1872}
1873
Hui Yingst8b5dfb22020-07-21 17:08:30 +00001874TEST_F(FPDFEditEmbedderTest, InsertAndRemoveLargeFile) {
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001875 const int kOriginalObjectCount = 600;
1876
1877 // Load document with many objects.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00001878 ASSERT_TRUE(OpenDocument("many_rectangles.pdf"));
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001879 FPDF_PAGE page = LoadPage(0);
1880 ASSERT_TRUE(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001881
1882 using pdfium::kManyRectanglesChecksum;
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001883 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001884 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001885 CompareBitmap(page_bitmap.get(), 200, 300, kManyRectanglesChecksum);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001886 }
1887
1888 // Add a black rectangle.
1889 ASSERT_EQ(kOriginalObjectCount, FPDFPage_CountObjects(page));
1890 FPDF_PAGEOBJECT black_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00001891 EXPECT_TRUE(FPDFPageObj_SetFillColor(black_rect, 0, 0, 0, 255));
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001892 EXPECT_TRUE(FPDFPath_SetDrawMode(black_rect, FPDF_FILLMODE_ALTERNATE, 0));
1893 FPDFPage_InsertObject(page, black_rect);
1894
1895 // Verify the black rectangle was added.
1896 ASSERT_EQ(kOriginalObjectCount + 1, FPDFPage_CountObjects(page));
Hui Yingst8b5dfb22020-07-21 17:08:30 +00001897#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
1898 const char kPlusRectangleMD5[] = "0d3715fcfb9bd0dd25dcce60800bff47";
1899#else
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001900 const char kPlusRectangleMD5[] = "6b9396ab570754b32b04ca629e902f77";
Hui Yingst8b5dfb22020-07-21 17:08:30 +00001901#endif
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001902 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001903 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001904 CompareBitmap(page_bitmap.get(), 200, 300, kPlusRectangleMD5);
1905 }
1906
1907 // Save the file.
1908 EXPECT_TRUE(FPDFPage_GenerateContent(page));
1909 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
1910 UnloadPage(page);
1911
1912 // Re-open the file and check the rectangle added is still there.
Lei Zhang0b494052019-01-31 21:41:15 +00001913 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001914 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001915 ASSERT_TRUE(saved_page);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001916 EXPECT_EQ(kOriginalObjectCount + 1, FPDFPage_CountObjects(saved_page));
1917 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001918 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001919 CompareBitmap(page_bitmap.get(), 200, 300, kPlusRectangleMD5);
1920 }
1921
1922 // Remove the added rectangle.
1923 FPDF_PAGEOBJECT added_object =
1924 FPDFPage_GetObject(saved_page, kOriginalObjectCount);
1925 EXPECT_TRUE(FPDFPage_RemoveObject(saved_page, added_object));
1926 FPDFPageObj_Destroy(added_object);
1927 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001928 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001929 CompareBitmap(page_bitmap.get(), 200, 300, kManyRectanglesChecksum);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001930 }
1931 EXPECT_EQ(kOriginalObjectCount, FPDFPage_CountObjects(saved_page));
1932
1933 // Save the file again.
1934 EXPECT_TRUE(FPDFPage_GenerateContent(saved_page));
Lei Zhang38e2b0e2021-11-05 00:28:05 +00001935 EXPECT_TRUE(FPDF_SaveAsCopy(saved_document(), this, 0));
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001936
1937 CloseSavedPage(saved_page);
1938 CloseSavedDocument();
1939
1940 // Re-open the file (again) and check the black rectangle was removed and the
1941 // rest is intact.
Lei Zhang0b494052019-01-31 21:41:15 +00001942 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001943 saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00001944 ASSERT_TRUE(saved_page);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001945 EXPECT_EQ(kOriginalObjectCount, FPDFPage_CountObjects(saved_page));
1946 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001947 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001948 CompareBitmap(page_bitmap.get(), 200, 300, kManyRectanglesChecksum);
Henrique Nakashima657a1aa2018-09-12 16:19:22 +00001949 }
1950
1951 CloseSavedPage(saved_page);
1952 CloseSavedDocument();
1953}
1954
Lei Zhangab41f252018-12-23 03:10:50 +00001955TEST_F(FPDFEditEmbedderTest, AddAndRemovePaths) {
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001956 // Start with a blank page.
1957 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
1958 ASSERT_TRUE(page);
1959
1960 // Render the blank page and verify it's a blank bitmap.
Hui Yingstb4baceb2020-04-28 23:46:10 +00001961 using pdfium::kBlankPage612By792Checksum;
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001962 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001963 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001964 CompareBitmap(page_bitmap.get(), 612, 792, kBlankPage612By792Checksum);
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001965 }
1966 ASSERT_EQ(0, FPDFPage_CountObjects(page));
1967
1968 // Add a red rectangle.
1969 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
1970 ASSERT_TRUE(red_rect);
Lei Zhang3475b482019-05-13 18:30:57 +00001971 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001972 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
1973 FPDFPage_InsertObject(page, red_rect);
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001974 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001975 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001976 CompareBitmap(page_bitmap.get(), 612, 792, kRedRectangleChecksum);
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001977 }
1978 EXPECT_EQ(1, FPDFPage_CountObjects(page));
1979
1980 // Remove rectangle and verify it does not render anymore and the bitmap is
1981 // back to a blank one.
1982 EXPECT_TRUE(FPDFPage_RemoveObject(page, red_rect));
1983 {
Lei Zhang30ff2532019-01-31 21:37:55 +00001984 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00001985 CompareBitmap(page_bitmap.get(), 612, 792, kBlankPage612By792Checksum);
Henrique Nakashima35841fa2018-03-15 15:25:16 +00001986 }
1987 EXPECT_EQ(0, FPDFPage_CountObjects(page));
1988
1989 // Trying to remove an object not in the page should return false.
1990 EXPECT_FALSE(FPDFPage_RemoveObject(page, red_rect));
1991
1992 FPDF_ClosePage(page);
1993 FPDFPageObj_Destroy(red_rect);
1994}
1995
Lei Zhangab41f252018-12-23 03:10:50 +00001996TEST_F(FPDFEditEmbedderTest, PathsPoints) {
Miklos Vajna12abfd02017-09-15 07:49:03 +02001997 CreateNewDocument();
Lei Zhang38e2b0e2021-11-05 00:28:05 +00001998 FPDF_PAGEOBJECT img = FPDFPageObj_NewImageObj(document());
Miklos Vajna12abfd02017-09-15 07:49:03 +02001999 // This should fail gracefully, even if img is not a path.
Miklos Vajna0150a542017-09-21 21:46:56 +02002000 ASSERT_EQ(-1, FPDFPath_CountSegments(img));
Miklos Vajna12abfd02017-09-15 07:49:03 +02002001
2002 // This should fail gracefully, even if path is NULL.
Miklos Vajna0150a542017-09-21 21:46:56 +02002003 ASSERT_EQ(-1, FPDFPath_CountSegments(nullptr));
Miklos Vajna12abfd02017-09-15 07:49:03 +02002004
Miklos Vajna36eed872017-09-20 22:52:43 +02002005 // FPDFPath_GetPathSegment() with a non-path.
2006 ASSERT_EQ(nullptr, FPDFPath_GetPathSegment(img, 0));
2007 // FPDFPath_GetPathSegment() with a NULL path.
2008 ASSERT_EQ(nullptr, FPDFPath_GetPathSegment(nullptr, 0));
2009 float x;
2010 float y;
2011 // FPDFPathSegment_GetPoint() with a NULL segment.
2012 EXPECT_FALSE(FPDFPathSegment_GetPoint(nullptr, &x, &y));
2013
2014 // FPDFPathSegment_GetType() with a NULL segment.
2015 ASSERT_EQ(FPDF_SEGMENT_UNKNOWN, FPDFPathSegment_GetType(nullptr));
2016
2017 // FPDFPathSegment_GetClose() with a NULL segment.
2018 EXPECT_FALSE(FPDFPathSegment_GetClose(nullptr));
2019
Miklos Vajna12abfd02017-09-15 07:49:03 +02002020 FPDFPageObj_Destroy(img);
2021}
2022
Hui Yingste95d5772020-08-24 23:58:26 +00002023TEST_F(FPDFEditEmbedderTest, PathOnTopOfText) {
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002024 // Load document with some text
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00002025 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002026 FPDF_PAGE page = LoadPage(0);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002027 ASSERT_TRUE(page);
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002028
2029 // Add an opaque rectangle on top of some of the text.
2030 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(20, 100, 50, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00002031 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002032 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
2033 FPDFPage_InsertObject(page, red_rect);
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002034
2035 // Add a transparent triangle on top of other part of the text.
2036 FPDF_PAGEOBJECT black_path = FPDFPageObj_CreateNewPath(20, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00002037 EXPECT_TRUE(FPDFPageObj_SetFillColor(black_path, 0, 0, 0, 100));
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002038 EXPECT_TRUE(FPDFPath_SetDrawMode(black_path, FPDF_FILLMODE_ALTERNATE, 0));
2039 EXPECT_TRUE(FPDFPath_LineTo(black_path, 30, 80));
2040 EXPECT_TRUE(FPDFPath_LineTo(black_path, 40, 10));
2041 EXPECT_TRUE(FPDFPath_Close(black_path));
2042 FPDFPage_InsertObject(page, black_path);
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002043
Hui Yingste95d5772020-08-24 23:58:26 +00002044 // Render and check the result.
Tom Sepeze08d2b12018-04-25 18:49:32 +00002045 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
Hui Yingste95d5772020-08-24 23:58:26 +00002046#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Hui Yingstbf9eee12022-05-25 21:20:24 +00002047 const char kChecksum[] = "8a48b019826492331454f2809990aba8";
Lei Zhang42d30c22022-01-12 19:24:43 +00002048#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002049 const char kChecksum[] = "279693baca9f48da2d75a8e289aed58e";
Hui Yingste95d5772020-08-24 23:58:26 +00002050#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00002051 const char kChecksum[] = "fe415d47945c10b9cc8e9ca08887369e";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -04002052#endif
Hui Yingste95d5772020-08-24 23:58:26 +00002053 CompareBitmap(bitmap.get(), 200, 200, kChecksum);
Nicolas Pena0fc185e2017-02-08 12:13:20 -05002054 UnloadPage(page);
2055}
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002056
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002057TEST_F(FPDFEditEmbedderTest, EditOverExistingContent) {
wileyryae858aa42017-05-31 14:49:05 -05002058 // Load document with existing content
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00002059 ASSERT_TRUE(OpenDocument("bug_717.pdf"));
wileyryae858aa42017-05-31 14:49:05 -05002060 FPDF_PAGE page = LoadPage(0);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002061 ASSERT_TRUE(page);
wileyryae858aa42017-05-31 14:49:05 -05002062
2063 // Add a transparent rectangle on top of the existing content
2064 FPDF_PAGEOBJECT red_rect2 = FPDFPageObj_CreateNewRect(90, 700, 25, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00002065 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect2, 255, 0, 0, 100));
wileyryae858aa42017-05-31 14:49:05 -05002066 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect2, FPDF_FILLMODE_ALTERNATE, 0));
2067 FPDFPage_InsertObject(page, red_rect2);
2068
2069 // Add an opaque rectangle on top of the existing content
2070 FPDF_PAGEOBJECT red_rect = FPDFPageObj_CreateNewRect(115, 700, 25, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00002071 EXPECT_TRUE(FPDFPageObj_SetFillColor(red_rect, 255, 0, 0, 255));
wileyryae858aa42017-05-31 14:49:05 -05002072 EXPECT_TRUE(FPDFPath_SetDrawMode(red_rect, FPDF_FILLMODE_ALTERNATE, 0));
2073 FPDFPage_InsertObject(page, red_rect);
2074
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002075#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2076 const char kOriginalChecksum[] = "1e82fbdd21490cee9d3479fe6125af67";
2077#else
2078 const char kOriginalChecksum[] = "ad04e5bd0f471a9a564fb034bd0fb073";
2079#endif
Tom Sepeze08d2b12018-04-25 18:49:32 +00002080 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002081 CompareBitmap(bitmap.get(), 612, 792, kOriginalChecksum);
wileyryae858aa42017-05-31 14:49:05 -05002082 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2083
2084 // Now save the result, closing the page and document
2085 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Nicolas Pena3ff54002017-07-05 11:55:35 -04002086 UnloadPage(page);
wileyryae858aa42017-05-31 14:49:05 -05002087
Lei Zhang0b494052019-01-31 21:41:15 +00002088 ASSERT_TRUE(OpenSavedDocument());
Lei Zhang107fa7b2018-02-09 21:48:15 +00002089 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00002090 ASSERT_TRUE(saved_page);
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002091 VerifySavedRendering(saved_page, 612, 792, kOriginalChecksum);
wileyryae858aa42017-05-31 14:49:05 -05002092
2093 ClearString();
2094 // Add another opaque rectangle on top of the existing content
2095 FPDF_PAGEOBJECT green_rect = FPDFPageObj_CreateNewRect(150, 700, 25, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00002096 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_rect, 0, 255, 0, 255));
wileyryae858aa42017-05-31 14:49:05 -05002097 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect, FPDF_FILLMODE_ALTERNATE, 0));
Lei Zhang107fa7b2018-02-09 21:48:15 +00002098 FPDFPage_InsertObject(saved_page, green_rect);
wileyryae858aa42017-05-31 14:49:05 -05002099
2100 // Add another transparent rectangle on top of existing content
2101 FPDF_PAGEOBJECT green_rect2 = FPDFPageObj_CreateNewRect(175, 700, 25, 50);
Lei Zhang3475b482019-05-13 18:30:57 +00002102 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_rect2, 0, 255, 0, 100));
wileyryae858aa42017-05-31 14:49:05 -05002103 EXPECT_TRUE(FPDFPath_SetDrawMode(green_rect2, FPDF_FILLMODE_ALTERNATE, 0));
Lei Zhang107fa7b2018-02-09 21:48:15 +00002104 FPDFPage_InsertObject(saved_page, green_rect2);
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002105#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2106 const char kLastChecksum[] = "8705d023e5fec3499d1e30cf2bcc5dc1";
2107#else
2108 const char kLastChecksum[] = "4b5b00f824620f8c9b8801ebb98e1cdd";
2109#endif
Lei Zhangc113c7a2018-02-12 14:58:44 +00002110 {
Tom Sepeze08d2b12018-04-25 18:49:32 +00002111 ScopedFPDFBitmap new_bitmap = RenderSavedPage(saved_page);
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002112 CompareBitmap(new_bitmap.get(), 612, 792, kLastChecksum);
Lei Zhangc113c7a2018-02-12 14:58:44 +00002113 }
Lei Zhang107fa7b2018-02-09 21:48:15 +00002114 EXPECT_TRUE(FPDFPage_GenerateContent(saved_page));
wileyryae858aa42017-05-31 14:49:05 -05002115
2116 // Now save the result, closing the page and document
Lei Zhang38e2b0e2021-11-05 00:28:05 +00002117 EXPECT_TRUE(FPDF_SaveAsCopy(saved_document(), this, 0));
Dan Sinclair04e4dc82017-10-18 12:17:14 -04002118
Lei Zhang107fa7b2018-02-09 21:48:15 +00002119 CloseSavedPage(saved_page);
Dan Sinclair04e4dc82017-10-18 12:17:14 -04002120 CloseSavedDocument();
wileyryae858aa42017-05-31 14:49:05 -05002121
2122 // Render the saved result
Hui Yingst1f73c4f2020-07-29 00:46:25 +00002123 VerifySavedDocument(612, 792, kLastChecksum);
wileyryae858aa42017-05-31 14:49:05 -05002124}
2125
Hui Yingst041116e2021-03-01 21:27:50 +00002126// TODO(crbug.com/pdfium/1651): Fix this issue and enable the test for Skia.
2127#if defined(_SKIA_SUPPORT_)
Lei Zhang03e5e682019-09-16 19:45:55 +00002128#define MAYBE_AddStrokedPaths DISABLED_AddStrokedPaths
2129#else
2130#define MAYBE_AddStrokedPaths AddStrokedPaths
2131#endif
2132TEST_F(FPDFEditEmbedderTest, MAYBE_AddStrokedPaths) {
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002133 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -05002134 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002135
2136 // Add a large stroked rectangle (fill color should not affect it).
2137 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(20, 20, 200, 400);
Lei Zhang3475b482019-05-13 18:30:57 +00002138 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect, 255, 0, 0, 255));
2139 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(rect, 0, 255, 0, 255));
2140 EXPECT_TRUE(FPDFPageObj_SetStrokeWidth(rect, 15.0f));
Miklos Vajna366df7f2018-05-22 14:27:29 +00002141
2142 float width = 0;
2143 EXPECT_TRUE(FPDFPageObj_GetStrokeWidth(rect, &width));
2144 EXPECT_EQ(15.0f, width);
2145
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002146 EXPECT_TRUE(FPDFPath_SetDrawMode(rect, 0, 1));
2147 FPDFPage_InsertObject(page, rect);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002148 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002149 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst041116e2021-03-01 21:27:50 +00002150#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2151 static constexpr char kChecksum_1[] = "1469acf60e7647ebeb8e1fb08c5d6c7a";
2152#else
2153 static constexpr char kChecksum_1[] = "64bd31f862a89e0a9e505a5af6efd506";
2154#endif
2155 CompareBitmap(page_bitmap.get(), 612, 792, kChecksum_1);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002156 }
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002157
2158 // Add crossed-checkmark
2159 FPDF_PAGEOBJECT check = FPDFPageObj_CreateNewPath(300, 500);
2160 EXPECT_TRUE(FPDFPath_LineTo(check, 400, 400));
2161 EXPECT_TRUE(FPDFPath_LineTo(check, 600, 600));
2162 EXPECT_TRUE(FPDFPath_MoveTo(check, 400, 600));
2163 EXPECT_TRUE(FPDFPath_LineTo(check, 600, 400));
Lei Zhang3475b482019-05-13 18:30:57 +00002164 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(check, 128, 128, 128, 180));
2165 EXPECT_TRUE(FPDFPageObj_SetStrokeWidth(check, 8.35f));
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002166 EXPECT_TRUE(FPDFPath_SetDrawMode(check, 0, 1));
2167 FPDFPage_InsertObject(page, check);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002168 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002169 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst041116e2021-03-01 21:27:50 +00002170#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2171 static constexpr char kChecksum_2[] = "68b3194f74abd9d471695ce1415be43f";
2172#else
2173 static constexpr char kChecksum_2[] = "4b6f3b9d25c4e194821217d5016c3724";
2174#endif
2175 CompareBitmap(page_bitmap.get(), 612, 792, kChecksum_2);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002176 }
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002177
2178 // Add stroked and filled oval-ish path.
2179 FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(250, 100);
2180 EXPECT_TRUE(FPDFPath_BezierTo(path, 180, 166, 180, 233, 250, 300));
2181 EXPECT_TRUE(FPDFPath_LineTo(path, 255, 305));
2182 EXPECT_TRUE(FPDFPath_BezierTo(path, 325, 233, 325, 166, 255, 105));
2183 EXPECT_TRUE(FPDFPath_Close(path));
Lei Zhang3475b482019-05-13 18:30:57 +00002184 EXPECT_TRUE(FPDFPageObj_SetFillColor(path, 200, 128, 128, 100));
2185 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(path, 128, 200, 128, 150));
2186 EXPECT_TRUE(FPDFPageObj_SetStrokeWidth(path, 10.5f));
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002187 EXPECT_TRUE(FPDFPath_SetDrawMode(path, FPDF_FILLMODE_ALTERNATE, 1));
2188 FPDFPage_InsertObject(page, path);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002189 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002190 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst041116e2021-03-01 21:27:50 +00002191#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
2192 static constexpr char kChecksum_3[] = "ea784068651df2b9ba132ce9215e6780";
2193#else
2194 static constexpr char kChecksum_3[] = "ff3e6a22326754944cc6e56609acd73b";
2195#endif
2196 CompareBitmap(page_bitmap.get(), 612, 792, kChecksum_3);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002197 }
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002198 FPDF_ClosePage(page);
Nicolas Pena2eb1a702017-02-09 18:17:33 -05002199}
Nicolas Pena49058402017-02-14 18:26:20 -05002200
Nicolas Pena4c48b102018-06-13 18:23:46 +00002201// Tests adding text from standard font using FPDFPageObj_NewTextObj.
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00002202TEST_F(FPDFEditEmbedderTest, AddStandardFontText) {
Nicolas Pena49058402017-02-14 18:26:20 -05002203 // Start with a blank page
Lei Zhang8496d132021-07-08 04:34:34 +00002204 ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
Nicolas Pena49058402017-02-14 18:26:20 -05002205
2206 // Add some text to the page
Nicolas Penab3161852017-05-02 14:12:50 -04002207 FPDF_PAGEOBJECT text_object1 =
2208 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
2209 EXPECT_TRUE(text_object1);
Hui Yingst3b6136a2020-06-09 00:39:33 +00002210 ScopedFPDFWideString text1 = GetFPDFWideString(kBottomText);
Nicolas Penab3161852017-05-02 14:12:50 -04002211 EXPECT_TRUE(FPDFText_SetText(text_object1, text1.get()));
Lei Zhangcfd08172021-06-30 04:11:21 +00002212 static constexpr FS_MATRIX kMatrix1{1, 0, 0, 1, 20, 20};
2213 EXPECT_TRUE(FPDFPageObj_SetMatrix(text_object1, &kMatrix1));
Lei Zhang8496d132021-07-08 04:34:34 +00002214 FPDFPage_InsertObject(page.get(), text_object1);
2215 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhang107fa7b2018-02-09 21:48:15 +00002216 {
Lei Zhang8496d132021-07-08 04:34:34 +00002217 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
Hui Yingst3b6136a2020-06-09 00:39:33 +00002218 CompareBitmap(page_bitmap.get(), 612, 792, kBottomTextChecksum);
Lei Zhange039bab2019-03-18 19:57:56 +00002219
2220 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Hui Yingst3b6136a2020-06-09 00:39:33 +00002221 VerifySavedDocument(612, 792, kBottomTextChecksum);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002222 }
Nicolas Pena49058402017-02-14 18:26:20 -05002223
2224 // Try another font
Nicolas Penab3161852017-05-02 14:12:50 -04002225 FPDF_PAGEOBJECT text_object2 =
Nicolas Penad03ca422017-03-06 13:54:33 -05002226 FPDFPageObj_NewTextObj(document(), "TimesNewRomanBold", 15.0f);
Nicolas Penab3161852017-05-02 14:12:50 -04002227 EXPECT_TRUE(text_object2);
Lei Zhangf0f67682019-04-08 17:03:21 +00002228 ScopedFPDFWideString text2 =
Nicolas Penab3161852017-05-02 14:12:50 -04002229 GetFPDFWideString(L"Hi, I'm Bold. Times New Roman Bold.");
2230 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
2231 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 600);
Lei Zhang8496d132021-07-08 04:34:34 +00002232 FPDFPage_InsertObject(page.get(), text_object2);
2233 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhang107fa7b2018-02-09 21:48:15 +00002234 {
Lei Zhang8496d132021-07-08 04:34:34 +00002235 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
Hui Yingstbf9eee12022-05-25 21:20:24 +00002236#if BUILDFLAG(IS_APPLE) && !defined(_SKIA_SUPPORT_) && \
2237 !defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002238 static constexpr char md5[] = "983baaa1f688eff7a14b1bf91c171a1a";
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00002239#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00002240 static constexpr char md5[] = "161523e196eb5341604cd73e12c97922";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -04002241#endif
Lei Zhange039bab2019-03-18 19:57:56 +00002242 CompareBitmap(page_bitmap.get(), 612, 792, md5);
2243
2244 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2245 VerifySavedDocument(612, 792, md5);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002246 }
Nicolas Pena49058402017-02-14 18:26:20 -05002247
2248 // And some randomly transformed text
Nicolas Penab3161852017-05-02 14:12:50 -04002249 FPDF_PAGEOBJECT text_object3 =
Nicolas Penad03ca422017-03-06 13:54:33 -05002250 FPDFPageObj_NewTextObj(document(), "Courier-Bold", 20.0f);
Nicolas Penab3161852017-05-02 14:12:50 -04002251 EXPECT_TRUE(text_object3);
Lei Zhangf0f67682019-04-08 17:03:21 +00002252 ScopedFPDFWideString text3 = GetFPDFWideString(L"Can you read me? <:)>");
Nicolas Penab3161852017-05-02 14:12:50 -04002253 EXPECT_TRUE(FPDFText_SetText(text_object3, text3.get()));
2254 FPDFPageObj_Transform(text_object3, 1, 1.5, 2, 0.5, 200, 200);
Lei Zhang8496d132021-07-08 04:34:34 +00002255 FPDFPage_InsertObject(page.get(), text_object3);
2256 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhang107fa7b2018-02-09 21:48:15 +00002257 {
Lei Zhang8496d132021-07-08 04:34:34 +00002258 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
Hui Yingstbf9eee12022-05-25 21:20:24 +00002259#if BUILDFLAG(IS_APPLE) && !defined(_SKIA_SUPPORT_) && \
2260 !defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002261 static constexpr char md5[] = "e0b3493c5c16e41d0d892ffb48e63fba";
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00002262#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00002263 static constexpr char md5[] = "1fbf772dca8d82b960631e6683934964";
Nicolas Pena5bcd9a32017-03-22 11:04:35 -04002264#endif
Lei Zhange039bab2019-03-18 19:57:56 +00002265 CompareBitmap(page_bitmap.get(), 612, 792, md5);
2266
2267 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2268 VerifySavedDocument(612, 792, md5);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002269 }
Nicolas Pena49058402017-02-14 18:26:20 -05002270
Lei Zhang8da98232019-12-11 23:29:33 +00002271 FS_MATRIX matrix;
Lei Zhangc8601bf2021-06-29 23:19:27 +00002272 EXPECT_TRUE(FPDFPageObj_GetMatrix(text_object3, &matrix));
Lei Zhang8da98232019-12-11 23:29:33 +00002273 EXPECT_FLOAT_EQ(1.0f, matrix.a);
2274 EXPECT_FLOAT_EQ(1.5f, matrix.b);
2275 EXPECT_FLOAT_EQ(2.0f, matrix.c);
2276 EXPECT_FLOAT_EQ(0.5f, matrix.d);
2277 EXPECT_FLOAT_EQ(200.0f, matrix.e);
2278 EXPECT_FLOAT_EQ(200.0f, matrix.f);
Miklos Vajnac765d2a2018-06-19 15:45:42 +00002279
Miklos Vajnad6d7ca72021-06-22 16:27:21 +00002280 EXPECT_FALSE(FPDFTextObj_GetFontSize(nullptr, nullptr));
Lei Zhang8496d132021-07-08 04:34:34 +00002281 float size = 55;
2282 EXPECT_FALSE(FPDFTextObj_GetFontSize(nullptr, &size));
2283 EXPECT_EQ(55, size);
Miklos Vajnad6d7ca72021-06-22 16:27:21 +00002284 EXPECT_TRUE(FPDFTextObj_GetFontSize(text_object3, &size));
2285 EXPECT_EQ(20, size);
Miklos Vajna8625d3b2018-06-26 15:12:48 +00002286
Nicolas Pena49058402017-02-14 18:26:20 -05002287 // TODO(npm): Why are there issues with text rotated by 90 degrees?
2288 // TODO(npm): FPDF_SaveAsCopy not giving the desired result after this.
Nicolas Pena49058402017-02-14 18:26:20 -05002289}
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002290
Lei Zhang20c52152021-06-18 20:37:10 +00002291TEST_F(FPDFEditEmbedderTest, AddStandardFontTextOfSizeZero) {
2292 // Start with a blank page
2293 ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
2294
2295 // Add some text of size 0 to the page.
2296 FPDF_PAGEOBJECT text_object =
2297 FPDFPageObj_NewTextObj(document(), "Arial", 0.0f);
2298 EXPECT_TRUE(text_object);
2299 ScopedFPDFWideString text = GetFPDFWideString(kBottomText);
2300 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
2301 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 20, 20);
2302
Miklos Vajnad6d7ca72021-06-22 16:27:21 +00002303 float size = -1; // Make sure 'size' gets changed.
2304 EXPECT_TRUE(FPDFTextObj_GetFontSize(text_object, &size));
2305 EXPECT_EQ(0.0f, size);
Lei Zhang20c52152021-06-18 20:37:10 +00002306
2307 FPDFPage_InsertObject(page.get(), text_object);
2308 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
2309 {
2310 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
2311 CompareBitmap(page_bitmap.get(), 612, 792,
2312 pdfium::kBlankPage612By792Checksum);
2313
2314 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2315 VerifySavedDocument(612, 792, pdfium::kBlankPage612By792Checksum);
2316 }
2317}
2318
Daniel Hosseinian8cb6a652019-12-18 00:50:41 +00002319TEST_F(FPDFEditEmbedderTest, GetTextRenderMode) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00002320 ASSERT_TRUE(OpenDocument("text_render_mode.pdf"));
Miklos Vajna1448cc12018-07-03 13:52:33 +00002321 FPDF_PAGE page = LoadPage(0);
2322 ASSERT_TRUE(page);
2323 ASSERT_EQ(2, FPDFPage_CountObjects(page));
2324
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002325 EXPECT_EQ(FPDF_TEXTRENDERMODE_UNKNOWN,
Daniel Hosseinian8cb6a652019-12-18 00:50:41 +00002326 FPDFTextObj_GetTextRenderMode(nullptr));
Miklos Vajna1448cc12018-07-03 13:52:33 +00002327
2328 FPDF_PAGEOBJECT fill = FPDFPage_GetObject(page, 0);
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002329 EXPECT_EQ(FPDF_TEXTRENDERMODE_FILL, FPDFTextObj_GetTextRenderMode(fill));
Miklos Vajna1448cc12018-07-03 13:52:33 +00002330
2331 FPDF_PAGEOBJECT stroke = FPDFPage_GetObject(page, 1);
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002332 EXPECT_EQ(FPDF_TEXTRENDERMODE_STROKE, FPDFTextObj_GetTextRenderMode(stroke));
2333
2334 UnloadPage(page);
2335}
2336
Hui Yingst9d8e5ec2020-07-30 22:33:22 +00002337TEST_F(FPDFEditEmbedderTest, SetTextRenderMode) {
Hui Yingst609f7d62020-04-23 23:14:13 +00002338#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Hui Yingstbf9eee12022-05-25 21:20:24 +00002339 const char kOriginalChecksum[] = "39a4ac8f1fdc6653edd3b91862ea7b75";
Tom Andersond4fe5f72021-12-03 20:52:52 +00002340 const char kStrokeChecksum[] = "d16eb1bb4748eeb5fb801594da70d519";
Lei Zhang42d30c22022-01-12 19:24:43 +00002341#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002342 const char kOriginalChecksum[] = "c488514ce0fc949069ff560407edacd2";
2343 const char kStrokeChecksum[] = "e06ee84aeebe926e8c980b7822027e8a";
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002344#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00002345 const char kOriginalChecksum[] = "97a4fcf3c9581e19917895631af31d41";
2346 const char kStrokeChecksum[] = "e06ee84aeebe926e8c980b7822027e8a";
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002347#endif
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002348
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002349 {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00002350 ASSERT_TRUE(OpenDocument("text_render_mode.pdf"));
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002351 FPDF_PAGE page = LoadPage(0);
2352 ASSERT_TRUE(page);
2353 ASSERT_EQ(2, FPDFPage_CountObjects(page));
2354
2355 // Check the bitmap
2356 {
2357 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst9d8e5ec2020-07-30 22:33:22 +00002358 CompareBitmap(page_bitmap.get(), 612, 446, kOriginalChecksum);
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002359 }
2360
2361 // Cannot set on a null object.
2362 EXPECT_FALSE(
2363 FPDFTextObj_SetTextRenderMode(nullptr, FPDF_TEXTRENDERMODE_UNKNOWN));
2364 EXPECT_FALSE(
2365 FPDFTextObj_SetTextRenderMode(nullptr, FPDF_TEXTRENDERMODE_INVISIBLE));
2366
2367 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
2368 ASSERT_TRUE(page_object);
2369 EXPECT_EQ(FPDF_TEXTRENDERMODE_FILL,
2370 FPDFTextObj_GetTextRenderMode(page_object));
2371
2372 // Cannot set UNKNOWN as a render mode.
2373 EXPECT_FALSE(FPDFTextObj_SetTextRenderMode(page_object,
2374 FPDF_TEXTRENDERMODE_UNKNOWN));
2375
2376 EXPECT_TRUE(
2377 FPDFTextObj_SetTextRenderMode(page_object, FPDF_TEXTRENDERMODE_STROKE));
2378 EXPECT_EQ(FPDF_TEXTRENDERMODE_STROKE,
2379 FPDFTextObj_GetTextRenderMode(page_object));
2380
2381 // Check that bitmap displays changed content
2382 {
2383 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst9d8e5ec2020-07-30 22:33:22 +00002384 CompareBitmap(page_bitmap.get(), 612, 446, kStrokeChecksum);
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002385 }
2386
Daniel Hosseinianafd27502020-07-01 04:59:03 +00002387 // Save a copy.
2388 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2389 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
2390
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002391 UnloadPage(page);
Daniel Hosseiniane83d8b42020-01-08 00:26:15 +00002392 }
Miklos Vajna1448cc12018-07-03 13:52:33 +00002393
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002394 {
Daniel Hosseinianafd27502020-07-01 04:59:03 +00002395 // Open the saved copy and render it. Check that the changed text render
2396 // mode is kept in the saved copy.
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002397 ASSERT_TRUE(OpenSavedDocument());
2398 FPDF_PAGE saved_page = LoadSavedPage(0);
2399 ASSERT_TRUE(saved_page);
2400
2401 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(saved_page, 0);
2402 EXPECT_TRUE(page_object);
Daniel Hosseinianafd27502020-07-01 04:59:03 +00002403 EXPECT_EQ(FPDF_TEXTRENDERMODE_STROKE,
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002404 FPDFTextObj_GetTextRenderMode(page_object));
2405
2406 ScopedFPDFBitmap bitmap = RenderSavedPage(saved_page);
Hui Yingst9d8e5ec2020-07-30 22:33:22 +00002407 CompareBitmap(bitmap.get(), 612, 446, kStrokeChecksum);
Daniel Hosseiniana933ebf2020-01-31 21:28:25 +00002408
2409 CloseSavedPage(saved_page);
2410 CloseSavedDocument();
2411 }
Miklos Vajna1448cc12018-07-03 13:52:33 +00002412}
2413
Robert Collyer68a18a02021-09-14 01:48:22 +00002414TEST_F(FPDFEditEmbedderTest, TextFontProperties) {
2415 // bad object tests
2416 EXPECT_FALSE(FPDFTextObj_GetFont(nullptr));
2417 EXPECT_EQ(0U, FPDFFont_GetFontName(nullptr, nullptr, 5));
2418 EXPECT_EQ(-1, FPDFFont_GetFlags(nullptr));
2419 EXPECT_EQ(-1, FPDFFont_GetWeight(nullptr));
2420 EXPECT_FALSE(FPDFFont_GetItalicAngle(nullptr, nullptr));
2421 EXPECT_FALSE(FPDFFont_GetAscent(nullptr, 12.f, nullptr));
2422 EXPECT_FALSE(FPDFFont_GetDescent(nullptr, 12.f, nullptr));
2423 EXPECT_FALSE(FPDFFont_GetGlyphWidth(nullptr, 's', 12.f, nullptr));
2424 EXPECT_FALSE(FPDFFont_GetGlyphPath(nullptr, 's', 12.f));
2425
2426 // good object tests
2427 ASSERT_TRUE(OpenDocument("text_font.pdf"));
2428 FPDF_PAGE page = LoadPage(0);
2429 ASSERT_TRUE(page);
2430 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2431 FPDF_PAGEOBJECT text = FPDFPage_GetObject(page, 0);
2432 ASSERT_TRUE(text);
2433 float font_size;
2434 ASSERT_TRUE(FPDFTextObj_GetFontSize(text, &font_size));
2435 FPDF_FONT font = FPDFTextObj_GetFont(text);
2436 ASSERT_TRUE(font);
2437
2438 // null return pointer tests
2439 EXPECT_FALSE(FPDFFont_GetItalicAngle(font, nullptr));
2440 EXPECT_FALSE(FPDFFont_GetAscent(font, font_size, nullptr));
2441 EXPECT_FALSE(FPDFFont_GetDescent(font, font_size, nullptr));
2442 EXPECT_FALSE(FPDFFont_GetGlyphWidth(font, 's', font_size, nullptr));
2443
2444 // correct property tests
2445 {
2446 EXPECT_EQ(4, FPDFFont_GetFlags(font));
2447 EXPECT_EQ(400, FPDFFont_GetWeight(font));
2448
2449 int angle;
2450 EXPECT_TRUE(FPDFFont_GetItalicAngle(font, &angle));
2451 EXPECT_EQ(0, angle);
2452
2453 float ascent;
2454 EXPECT_TRUE(FPDFFont_GetAscent(font, font_size, &ascent));
2455 EXPECT_FLOAT_EQ(891 * font_size / 1000.0f, ascent);
2456
2457 float descent;
2458 EXPECT_TRUE(FPDFFont_GetDescent(font, font_size, &descent));
2459 EXPECT_FLOAT_EQ(-216 * font_size / 1000.0f, descent);
2460
2461 float a12;
2462 float a24;
2463 EXPECT_TRUE(FPDFFont_GetGlyphWidth(font, 'a', 12.0f, &a12));
2464 EXPECT_FLOAT_EQ(a12, 5.316f);
2465 EXPECT_TRUE(FPDFFont_GetGlyphWidth(font, 'a', 24.0f, &a24));
2466 EXPECT_FLOAT_EQ(a24, 10.632f);
2467 }
2468
2469 {
2470 // FPDFFont_GetFontName() positive testing.
2471 unsigned long size = FPDFFont_GetFontName(font, nullptr, 0);
2472 const char kExpectedFontName[] = "Liberation Serif";
2473 ASSERT_EQ(sizeof(kExpectedFontName), size);
2474 std::vector<char> font_name(size);
2475 ASSERT_EQ(size, FPDFFont_GetFontName(font, font_name.data(), size));
2476 ASSERT_STREQ(kExpectedFontName, font_name.data());
2477
2478 // FPDFFont_GetFontName() negative testing.
2479 ASSERT_EQ(0U, FPDFFont_GetFontName(nullptr, nullptr, 0));
2480
2481 font_name.resize(2);
2482 font_name[0] = 'x';
2483 font_name[1] = '\0';
2484 size = FPDFFont_GetFontName(font, font_name.data(), font_name.size());
2485 ASSERT_EQ(sizeof(kExpectedFontName), size);
2486 ASSERT_STREQ("x", font_name.data());
2487 }
2488
Lei Zhangd2fc95d2022-05-11 19:38:35 +00002489 {
2490 // FPDFFont_GetFontData() positive testing.
2491 constexpr size_t kExpectedSize = 8268;
2492 std::vector<uint8_t> buf;
2493 size_t buf_bytes_required = 123;
2494 ASSERT_TRUE(FPDFFont_GetFontData(font, nullptr, 0, &buf_bytes_required));
2495 ASSERT_EQ(kExpectedSize, buf_bytes_required);
2496
2497 buf.resize(kExpectedSize);
2498 EXPECT_EQ("495800b8e56e2d37f3bc48a1b52db952", GenerateMD5Base16(buf));
2499 buf_bytes_required = 234;
2500 // Test with buffer that is too small. Make sure `buf` is unchanged.
2501 EXPECT_TRUE(FPDFFont_GetFontData(font, buf.data(), buf.size() - 1,
2502 &buf_bytes_required));
2503 EXPECT_EQ("495800b8e56e2d37f3bc48a1b52db952", GenerateMD5Base16(buf));
2504 EXPECT_EQ(kExpectedSize, buf_bytes_required);
2505
2506 // Test with buffer of the correct size.
2507 buf_bytes_required = 234;
2508 EXPECT_TRUE(FPDFFont_GetFontData(font, buf.data(), buf.size(),
2509 &buf_bytes_required));
2510 EXPECT_EQ("1a67be75f719b6c476804d85bb9e4844", GenerateMD5Base16(buf));
2511 EXPECT_EQ(kExpectedSize, buf_bytes_required);
2512
2513 // FPDFFont_GetFontData() negative testing.
2514 EXPECT_FALSE(FPDFFont_GetFontData(nullptr, nullptr, 0, nullptr));
2515 EXPECT_FALSE(FPDFFont_GetFontData(font, nullptr, 0, nullptr));
2516
2517 buf_bytes_required = 345;
2518 EXPECT_FALSE(
2519 FPDFFont_GetFontData(nullptr, nullptr, 0, &buf_bytes_required));
2520 EXPECT_EQ(345u, buf_bytes_required);
2521
2522 EXPECT_FALSE(
2523 FPDFFont_GetFontData(nullptr, buf.data(), buf.size(), nullptr));
2524 EXPECT_FALSE(FPDFFont_GetFontData(font, buf.data(), buf.size(), nullptr));
2525
2526 buf_bytes_required = 345;
2527 EXPECT_FALSE(FPDFFont_GetFontData(nullptr, buf.data(), buf.size(),
2528 &buf_bytes_required));
2529 EXPECT_EQ(345u, buf_bytes_required);
2530 }
Lei Zhange617ccd2022-05-11 19:50:35 +00002531 {
2532 ASSERT_EQ(1, FPDFFont_GetIsEmbedded(font));
2533 ASSERT_EQ(-1, FPDFFont_GetIsEmbedded(nullptr));
2534 }
Lei Zhangd2fc95d2022-05-11 19:38:35 +00002535
2536 UnloadPage(page);
2537}
2538
2539TEST_F(FPDFEditEmbedderTest, NoEmbeddedFontData) {
2540 ASSERT_TRUE(OpenDocument("hello_world.pdf"));
2541 FPDF_PAGE page = LoadPage(0);
2542 ASSERT_TRUE(page);
2543 ASSERT_EQ(2, FPDFPage_CountObjects(page));
2544
2545 // Since hello_world.pdf does not embed any font data, FPDFFont_GetFontData()
2546 // will return the substitution font data. Since pdfium_embeddertest is
2547 // hermetic, this first object consistently maps to Tinos-Regular.ttf.
2548 constexpr size_t kTinosRegularSize = 469968;
2549 FPDF_PAGEOBJECT text = FPDFPage_GetObject(page, 0);
2550 ASSERT_TRUE(text);
2551 FPDF_FONT font = FPDFTextObj_GetFont(text);
2552 ASSERT_TRUE(font);
2553 std::vector<uint8_t> buf;
2554 buf.resize(kTinosRegularSize);
2555 size_t buf_bytes_required;
2556 ASSERT_TRUE(
2557 FPDFFont_GetFontData(font, buf.data(), buf.size(), &buf_bytes_required));
2558 EXPECT_EQ(kTinosRegularSize, buf_bytes_required);
2559 EXPECT_EQ("2b019558f2c2de0b7cbc0a6e64b20599", GenerateMD5Base16(buf));
Lei Zhange617ccd2022-05-11 19:50:35 +00002560 EXPECT_EQ(0, FPDFFont_GetIsEmbedded(font));
Lei Zhangd2fc95d2022-05-11 19:38:35 +00002561
2562 // Similarly, the second object consistently maps to Arimo-Regular.ttf.
2563 constexpr size_t kArimoRegularSize = 436180;
2564 text = FPDFPage_GetObject(page, 1);
2565 ASSERT_TRUE(text);
2566 font = FPDFTextObj_GetFont(text);
2567 ASSERT_TRUE(font);
2568 buf.resize(kArimoRegularSize);
2569 ASSERT_TRUE(
2570 FPDFFont_GetFontData(font, buf.data(), buf.size(), &buf_bytes_required));
2571 EXPECT_EQ(kArimoRegularSize, buf_bytes_required);
2572 EXPECT_EQ("7ac02a544211773d9636e056e9da6c35", GenerateMD5Base16(buf));
Lei Zhange617ccd2022-05-11 19:50:35 +00002573 EXPECT_EQ(0, FPDFFont_GetIsEmbedded(font));
Lei Zhangd2fc95d2022-05-11 19:38:35 +00002574
Robert Collyer68a18a02021-09-14 01:48:22 +00002575 UnloadPage(page);
2576}
2577
2578TEST_F(FPDFEditEmbedderTest, GlyphPaths) {
2579 // bad glyphpath
2580 EXPECT_EQ(-1, FPDFGlyphPath_CountGlyphSegments(nullptr));
2581 EXPECT_FALSE(FPDFGlyphPath_GetGlyphPathSegment(nullptr, 1));
2582
2583 ASSERT_TRUE(OpenDocument("text_font.pdf"));
2584 FPDF_PAGE page = LoadPage(0);
2585 ASSERT_TRUE(page);
2586 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2587 FPDF_PAGEOBJECT text = FPDFPage_GetObject(page, 0);
2588 ASSERT_TRUE(text);
2589 FPDF_FONT font = FPDFTextObj_GetFont(text);
2590 ASSERT_TRUE(font);
2591
2592 // good glyphpath
2593 FPDF_GLYPHPATH gpath = FPDFFont_GetGlyphPath(font, 's', 12.0f);
2594 ASSERT_TRUE(gpath);
2595
2596 int count = FPDFGlyphPath_CountGlyphSegments(gpath);
2597 ASSERT_GT(count, 0);
2598 EXPECT_FALSE(FPDFGlyphPath_GetGlyphPathSegment(gpath, -1));
2599 EXPECT_FALSE(FPDFGlyphPath_GetGlyphPathSegment(gpath, count));
2600
2601 FPDF_PATHSEGMENT segment = FPDFGlyphPath_GetGlyphPathSegment(gpath, 1);
2602 ASSERT_TRUE(segment);
2603 EXPECT_EQ(FPDF_SEGMENT_BEZIERTO, FPDFPathSegment_GetType(segment));
2604
2605 UnloadPage(page);
2606}
2607
Lei Zhang4363dab2021-06-24 19:23:09 +00002608TEST_F(FPDFEditEmbedderTest, FormGetObjects) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00002609 ASSERT_TRUE(OpenDocument("form_object.pdf"));
Miklos Vajnab66077d2018-07-11 13:25:02 +00002610 FPDF_PAGE page = LoadPage(0);
2611 ASSERT_TRUE(page);
2612 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2613
2614 FPDF_PAGEOBJECT form = FPDFPage_GetObject(page, 0);
Lei Zhang4363dab2021-06-24 19:23:09 +00002615 ASSERT_EQ(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(form));
Miklos Vajnab66077d2018-07-11 13:25:02 +00002616 ASSERT_EQ(-1, FPDFFormObj_CountObjects(nullptr));
2617 ASSERT_EQ(2, FPDFFormObj_CountObjects(form));
2618
Miklos Vajna1d273f12018-07-16 19:20:36 +00002619 // FPDFFormObj_GetObject() positive testing.
2620 FPDF_PAGEOBJECT text1 = FPDFFormObj_GetObject(form, 0);
2621 ASSERT_TRUE(text1);
2622 float left = 0;
2623 float bottom = 0;
2624 float right = 0;
2625 float top = 0;
2626 ASSERT_TRUE(FPDFPageObj_GetBounds(text1, &left, &bottom, &right, &top));
2627 ASSERT_EQ(271, static_cast<int>(top));
2628
2629 FPDF_PAGEOBJECT text2 = FPDFFormObj_GetObject(form, 1);
2630 ASSERT_TRUE(text2);
2631 ASSERT_TRUE(FPDFPageObj_GetBounds(text2, &left, &bottom, &right, &top));
2632 ASSERT_EQ(221, static_cast<int>(top));
2633
2634 // FPDFFormObj_GetObject() negative testing.
2635 ASSERT_EQ(nullptr, FPDFFormObj_GetObject(nullptr, 0));
2636 ASSERT_EQ(nullptr, FPDFFormObj_GetObject(form, -1));
2637 ASSERT_EQ(nullptr, FPDFFormObj_GetObject(form, 2));
2638
Lei Zhangc8601bf2021-06-29 23:19:27 +00002639 // FPDFPageObj_GetMatrix() positive testing for forms.
Lei Zhang8da98232019-12-11 23:29:33 +00002640 static constexpr FS_MATRIX kMatrix = {1.0f, 1.5f, 2.0f, 2.5f, 100.0f, 200.0f};
Lei Zhang2193da92021-06-30 01:03:07 +00002641 EXPECT_TRUE(FPDFPageObj_SetMatrix(form, &kMatrix));
Miklos Vajna46b43732018-08-14 19:15:43 +00002642
Lei Zhang8da98232019-12-11 23:29:33 +00002643 FS_MATRIX matrix;
Lei Zhangc8601bf2021-06-29 23:19:27 +00002644 EXPECT_TRUE(FPDFPageObj_GetMatrix(form, &matrix));
Lei Zhang8da98232019-12-11 23:29:33 +00002645 EXPECT_FLOAT_EQ(kMatrix.a, matrix.a);
2646 EXPECT_FLOAT_EQ(kMatrix.b, matrix.b);
2647 EXPECT_FLOAT_EQ(kMatrix.c, matrix.c);
2648 EXPECT_FLOAT_EQ(kMatrix.d, matrix.d);
2649 EXPECT_FLOAT_EQ(kMatrix.e, matrix.e);
2650 EXPECT_FLOAT_EQ(kMatrix.f, matrix.f);
Miklos Vajna46b43732018-08-14 19:15:43 +00002651
Lei Zhangc8601bf2021-06-29 23:19:27 +00002652 // FPDFPageObj_GetMatrix() negative testing for forms.
2653 EXPECT_FALSE(FPDFPageObj_GetMatrix(form, nullptr));
Miklos Vajna46b43732018-08-14 19:15:43 +00002654
Miklos Vajnab66077d2018-07-11 13:25:02 +00002655 UnloadPage(page);
2656}
2657
Lei Zhang4363dab2021-06-24 19:23:09 +00002658TEST_F(FPDFEditEmbedderTest, ModifyFormObject) {
Hui Yingstbf9eee12022-05-25 21:20:24 +00002659#if BUILDFLAG(IS_APPLE) && !defined(_SKIA_SUPPORT_) && \
2660 !defined(_SKIA_SUPPORT_PATHS_)
Tom Andersond4fe5f72021-12-03 20:52:52 +00002661 const char kOrigChecksum[] = "a637057185f50aac1aa5490f726aef95";
2662 const char kNewChecksum[] = "8ad9d79b02b609ff734e2a2195c96e2d";
Lei Zhang4363dab2021-06-24 19:23:09 +00002663#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00002664 const char kOrigChecksum[] = "34a9ec0a9581a7970e073c0bcc4ca676";
2665 const char kNewChecksum[] = "609b5632a21c886fa93182dbc290bf7a";
2666#endif
Lei Zhang4363dab2021-06-24 19:23:09 +00002667
2668 ASSERT_TRUE(OpenDocument("form_object.pdf"));
2669 FPDF_PAGE page = LoadPage(0);
2670 ASSERT_TRUE(page);
2671 ASSERT_EQ(1, FPDFPage_CountObjects(page));
2672
2673 {
2674 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
2675 CompareBitmap(bitmap.get(), 62, 69, kOrigChecksum);
2676 }
2677
2678 FPDF_PAGEOBJECT form = FPDFPage_GetObject(page, 0);
2679 ASSERT_EQ(FPDF_PAGEOBJ_FORM, FPDFPageObj_GetType(form));
2680
Lei Zhang651113b2021-06-25 20:03:25 +00002681 FPDFPageObj_Transform(form, 0.5, 0, 0, 0.5, 0, 0);
Lei Zhang4363dab2021-06-24 19:23:09 +00002682 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2683
2684 {
2685 ScopedFPDFBitmap bitmap = RenderLoadedPage(page);
2686 CompareBitmap(bitmap.get(), 62, 69, kNewChecksum);
2687 }
2688
Lei Zhang4363dab2021-06-24 19:23:09 +00002689 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
Lei Zhangac7f0e12021-06-24 19:38:00 +00002690 VerifySavedDocument(62, 69, kNewChecksum);
Lei Zhang4363dab2021-06-24 19:23:09 +00002691
2692 UnloadPage(page);
2693}
2694
Nicolas Pena4c48b102018-06-13 18:23:46 +00002695// Tests adding text from standard font using FPDFText_LoadStandardFont.
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00002696TEST_F(FPDFEditEmbedderTest, AddStandardFontText2) {
Nicolas Pena4c48b102018-06-13 18:23:46 +00002697 // Start with a blank page
2698 ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
2699
2700 // Load a standard font.
Tom Sepezffff6c52019-07-30 21:56:19 +00002701 ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), "Helvetica"));
Nicolas Pena4c48b102018-06-13 18:23:46 +00002702 ASSERT_TRUE(font);
2703
2704 // Add some text to the page.
2705 FPDF_PAGEOBJECT text_object =
Tom Sepezffff6c52019-07-30 21:56:19 +00002706 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
Nicolas Pena4c48b102018-06-13 18:23:46 +00002707 EXPECT_TRUE(text_object);
Hui Yingst3b6136a2020-06-09 00:39:33 +00002708 ScopedFPDFWideString text = GetFPDFWideString(kBottomText);
Nicolas Pena4c48b102018-06-13 18:23:46 +00002709 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
2710 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 20, 20);
2711 FPDFPage_InsertObject(page.get(), text_object);
Lei Zhang30ff2532019-01-31 21:37:55 +00002712 ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
Hui Yingst3b6136a2020-06-09 00:39:33 +00002713 CompareBitmap(page_bitmap.get(), 612, 792, kBottomTextChecksum);
Nicolas Pena4c48b102018-06-13 18:23:46 +00002714}
2715
Lei Zhangab41f252018-12-23 03:10:50 +00002716TEST_F(FPDFEditEmbedderTest, LoadStandardFonts) {
Nicolas Pena4c48b102018-06-13 18:23:46 +00002717 CreateNewDocument();
Lei Zhang590f4242019-05-15 20:57:26 +00002718 static constexpr const char* kStandardFontNames[] = {
Lei Zhangd72fd582018-07-27 19:37:27 +00002719 "Arial",
2720 "Arial-Bold",
2721 "Arial-BoldItalic",
2722 "Arial-Italic",
2723 "Courier",
2724 "Courier-BoldOblique",
2725 "Courier-Oblique",
2726 "Courier-Bold",
2727 "CourierNew",
2728 "CourierNew-Bold",
2729 "CourierNew-BoldItalic",
2730 "CourierNew-Italic",
2731 "Helvetica",
2732 "Helvetica-Bold",
2733 "Helvetica-BoldOblique",
2734 "Helvetica-Oblique",
2735 "Symbol",
2736 "TimesNewRoman",
2737 "TimesNewRoman-Bold",
2738 "TimesNewRoman-BoldItalic",
2739 "TimesNewRoman-Italic",
2740 "ZapfDingbats"};
Lei Zhang590f4242019-05-15 20:57:26 +00002741 for (const char* font_name : kStandardFontNames) {
Tom Sepezffff6c52019-07-30 21:56:19 +00002742 ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), font_name));
Nicolas Pena4c48b102018-06-13 18:23:46 +00002743 EXPECT_TRUE(font) << font_name << " should be considered a standard font.";
2744 }
Lei Zhang590f4242019-05-15 20:57:26 +00002745 static constexpr const char* kNotStandardFontNames[] = {
Nicolas Pena4c48b102018-06-13 18:23:46 +00002746 "Abcdefg", "ArialB", "Arial-Style",
2747 "Font Name", "FontArial", "NotAStandardFontName",
2748 "TestFontName", "Quack", "Symbol-Italic",
2749 "Zapf"};
Lei Zhang590f4242019-05-15 20:57:26 +00002750 for (const char* font_name : kNotStandardFontNames) {
Tom Sepezffff6c52019-07-30 21:56:19 +00002751 ScopedFPDFFont font(FPDFText_LoadStandardFont(document(), font_name));
Nicolas Pena4c48b102018-06-13 18:23:46 +00002752 EXPECT_FALSE(font) << font_name
2753 << " should not be considered a standard font.";
2754 }
2755}
2756
Lei Zhangab41f252018-12-23 03:10:50 +00002757TEST_F(FPDFEditEmbedderTest, GraphicsData) {
Nicolas Pena603a31d2017-06-14 11:41:18 -04002758 // New page
Tom Sepeze08d2b12018-04-25 18:49:32 +00002759 ScopedFPDFPage page(FPDFPage_New(CreateNewDocument(), 0, 612, 792));
Nicolas Pena603a31d2017-06-14 11:41:18 -04002760
2761 // Create a rect with nontrivial graphics
2762 FPDF_PAGEOBJECT rect1 = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
2763 FPDFPageObj_SetBlendMode(rect1, "Color");
2764 FPDFPage_InsertObject(page.get(), rect1);
2765 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
2766
2767 // Check that the ExtGState was created
Lei Zhang107fa7b2018-02-09 21:48:15 +00002768 CPDF_Page* cpage = CPDFPageFromFPDFPage(page.get());
Tom Sepezc8155092021-04-26 23:37:42 +00002769 const CPDF_Dictionary* graphics_dict =
2770 cpage->GetResources()->GetDictFor("ExtGState");
Nicolas Pena603a31d2017-06-14 11:41:18 -04002771 ASSERT_TRUE(graphics_dict);
Lei Zhangf40380f2018-10-12 18:31:51 +00002772 EXPECT_EQ(2u, graphics_dict->size());
Nicolas Pena603a31d2017-06-14 11:41:18 -04002773
2774 // Add a text object causing no change to the graphics dictionary
2775 FPDF_PAGEOBJECT text1 = FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
2776 // Only alpha, the last component, matters for the graphics dictionary. And
2777 // the default value is 255.
Lei Zhang3475b482019-05-13 18:30:57 +00002778 EXPECT_TRUE(FPDFPageObj_SetFillColor(text1, 100, 100, 100, 255));
Nicolas Pena603a31d2017-06-14 11:41:18 -04002779 FPDFPage_InsertObject(page.get(), text1);
2780 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhangf40380f2018-10-12 18:31:51 +00002781 EXPECT_EQ(2u, graphics_dict->size());
Nicolas Pena603a31d2017-06-14 11:41:18 -04002782
2783 // Add a text object increasing the size of the graphics dictionary
2784 FPDF_PAGEOBJECT text2 =
2785 FPDFPageObj_NewTextObj(document(), "Times-Roman", 12.0f);
2786 FPDFPage_InsertObject(page.get(), text2);
2787 FPDFPageObj_SetBlendMode(text2, "Darken");
Lei Zhang3475b482019-05-13 18:30:57 +00002788 EXPECT_TRUE(FPDFPageObj_SetFillColor(text2, 0, 0, 255, 150));
Nicolas Pena603a31d2017-06-14 11:41:18 -04002789 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhangf40380f2018-10-12 18:31:51 +00002790 EXPECT_EQ(3u, graphics_dict->size());
Nicolas Pena603a31d2017-06-14 11:41:18 -04002791
2792 // Add a path that should reuse graphics
Nicolas Penace67be42017-06-14 14:52:49 -04002793 FPDF_PAGEOBJECT path = FPDFPageObj_CreateNewPath(400, 100);
Nicolas Pena603a31d2017-06-14 11:41:18 -04002794 FPDFPageObj_SetBlendMode(path, "Darken");
Lei Zhang3475b482019-05-13 18:30:57 +00002795 EXPECT_TRUE(FPDFPageObj_SetFillColor(path, 200, 200, 100, 150));
Nicolas Pena603a31d2017-06-14 11:41:18 -04002796 FPDFPage_InsertObject(page.get(), path);
2797 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhangf40380f2018-10-12 18:31:51 +00002798 EXPECT_EQ(3u, graphics_dict->size());
Nicolas Pena603a31d2017-06-14 11:41:18 -04002799
2800 // Add a rect increasing the size of the graphics dictionary
2801 FPDF_PAGEOBJECT rect2 = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
2802 FPDFPageObj_SetBlendMode(rect2, "Darken");
Lei Zhang3475b482019-05-13 18:30:57 +00002803 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect2, 0, 0, 255, 150));
2804 EXPECT_TRUE(FPDFPageObj_SetStrokeColor(rect2, 0, 0, 0, 200));
Nicolas Pena603a31d2017-06-14 11:41:18 -04002805 FPDFPage_InsertObject(page.get(), rect2);
2806 EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
Lei Zhangf40380f2018-10-12 18:31:51 +00002807 EXPECT_EQ(4u, graphics_dict->size());
Nicolas Pena603a31d2017-06-14 11:41:18 -04002808}
2809
Lei Zhangab41f252018-12-23 03:10:50 +00002810TEST_F(FPDFEditEmbedderTest, DoubleGenerating) {
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002811 // Start with a blank page
Nicolas Penad03ca422017-03-06 13:54:33 -05002812 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002813
2814 // Add a red rectangle with some non-default alpha
2815 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 100, 100);
Lei Zhang3475b482019-05-13 18:30:57 +00002816 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect, 255, 0, 0, 128));
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002817 EXPECT_TRUE(FPDFPath_SetDrawMode(rect, FPDF_FILLMODE_WINDING, 0));
2818 FPDFPage_InsertObject(page, rect);
2819 EXPECT_TRUE(FPDFPage_GenerateContent(page));
2820
2821 // Check the ExtGState
Lei Zhang107fa7b2018-02-09 21:48:15 +00002822 CPDF_Page* cpage = CPDFPageFromFPDFPage(page);
Tom Sepezc8155092021-04-26 23:37:42 +00002823 const CPDF_Dictionary* graphics_dict =
2824 cpage->GetResources()->GetDictFor("ExtGState");
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002825 ASSERT_TRUE(graphics_dict);
Lei Zhangf40380f2018-10-12 18:31:51 +00002826 EXPECT_EQ(2u, graphics_dict->size());
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002827
2828 // Check the bitmap
Lei Zhang107fa7b2018-02-09 21:48:15 +00002829 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002830 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002831 CompareBitmap(page_bitmap.get(), 612, 792,
2832 "5384da3406d62360ffb5cac4476fff1c");
2833 }
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002834
2835 // Never mind, my new favorite color is blue, increase alpha
Lei Zhang3475b482019-05-13 18:30:57 +00002836 EXPECT_TRUE(FPDFPageObj_SetFillColor(rect, 0, 0, 255, 180));
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002837 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Lei Zhangf40380f2018-10-12 18:31:51 +00002838 EXPECT_EQ(3u, graphics_dict->size());
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002839
2840 // Check that bitmap displays changed content
Lei Zhang107fa7b2018-02-09 21:48:15 +00002841 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002842 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002843 CompareBitmap(page_bitmap.get(), 612, 792,
2844 "2e51656f5073b0bee611d9cd086aa09c");
2845 }
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002846
2847 // And now generate, without changes
2848 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Lei Zhangf40380f2018-10-12 18:31:51 +00002849 EXPECT_EQ(3u, graphics_dict->size());
Lei Zhang107fa7b2018-02-09 21:48:15 +00002850 {
Lei Zhang30ff2532019-01-31 21:37:55 +00002851 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +00002852 CompareBitmap(page_bitmap.get(), 612, 792,
2853 "2e51656f5073b0bee611d9cd086aa09c");
2854 }
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002855
2856 // Add some text to the page
Nicolas Penab3161852017-05-02 14:12:50 -04002857 FPDF_PAGEOBJECT text_object =
2858 FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
Lei Zhangf0f67682019-04-08 17:03:21 +00002859 ScopedFPDFWideString text =
Nicolas Penab3161852017-05-02 14:12:50 -04002860 GetFPDFWideString(L"Something something #text# something");
2861 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
2862 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 300, 300);
2863 FPDFPage_InsertObject(page, text_object);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002864 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Tom Sepezc8155092021-04-26 23:37:42 +00002865 const CPDF_Dictionary* font_dict = cpage->GetResources()->GetDictFor("Font");
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002866 ASSERT_TRUE(font_dict);
Lei Zhangf40380f2018-10-12 18:31:51 +00002867 EXPECT_EQ(1u, font_dict->size());
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002868
2869 // Generate yet again, check dicts are reasonably sized
2870 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Lei Zhangf40380f2018-10-12 18:31:51 +00002871 EXPECT_EQ(3u, graphics_dict->size());
2872 EXPECT_EQ(1u, font_dict->size());
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002873 FPDF_ClosePage(page);
Nicolas Penaa4ad01f2017-02-15 16:26:48 -05002874}
Nicolas Penabe90aae2017-02-27 10:41:41 -05002875
Lei Zhangab41f252018-12-23 03:10:50 +00002876TEST_F(FPDFEditEmbedderTest, LoadSimpleType1Font) {
Nicolas Penad03ca422017-03-06 13:54:33 -05002877 CreateNewDocument();
2878 // TODO(npm): use other fonts after disallowing loading any font as any type
Tom Sepezffff6c52019-07-30 21:56:19 +00002879 RetainPtr<CPDF_Font> stock_font =
Nicolas Penad03ca422017-03-06 13:54:33 -05002880 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Bold");
Tom Sepez20c41a52018-08-29 23:53:53 +00002881 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2882 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2883 FPDF_FONT_TYPE1, false));
Nicolas Penab3161852017-05-02 14:12:50 -04002884 ASSERT_TRUE(font.get());
Tom Sepez525147a2018-05-03 17:19:53 +00002885 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -05002886 EXPECT_TRUE(typed_font->IsType1Font());
Nicolas Penabe90aae2017-02-27 10:41:41 -05002887
Lei Zhang710fa992018-05-25 16:24:48 +00002888 const CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Lei Zhanga228ff32020-06-24 17:39:33 +00002889 EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
2890 EXPECT_EQ("Type1", font_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00002891 EXPECT_EQ("Tinos-Bold", font_dict->GetNameFor("BaseFont"));
Nicolas Penabe90aae2017-02-27 10:41:41 -05002892 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
2893 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
2894 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
Nicolas Penad03ca422017-03-06 13:54:33 -05002895 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
2896
Lei Zhangde579ab2018-05-25 21:49:49 +00002897 const CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
Nicolas Penad03ca422017-03-06 13:54:33 -05002898 ASSERT_TRUE(widths_array);
Lei Zhangf40380f2018-10-12 18:31:51 +00002899 ASSERT_EQ(224u, widths_array->size());
Nicolas Penabe90aae2017-02-27 10:41:41 -05002900 EXPECT_EQ(250, widths_array->GetNumberAt(0));
Nicolas Penad03ca422017-03-06 13:54:33 -05002901 EXPECT_EQ(569, widths_array->GetNumberAt(11));
2902 EXPECT_EQ(500, widths_array->GetNumberAt(223));
Tom Sepez20c41a52018-08-29 23:53:53 +00002903 CheckFontDescriptor(font_dict, FPDF_FONT_TYPE1, true, false, span);
Nicolas Penad03ca422017-03-06 13:54:33 -05002904}
Nicolas Penabe90aae2017-02-27 10:41:41 -05002905
Lei Zhangab41f252018-12-23 03:10:50 +00002906TEST_F(FPDFEditEmbedderTest, LoadSimpleTrueTypeFont) {
Nicolas Penad03ca422017-03-06 13:54:33 -05002907 CreateNewDocument();
Tom Sepezffff6c52019-07-30 21:56:19 +00002908 RetainPtr<CPDF_Font> stock_font =
2909 CPDF_Font::GetStockFont(cpdf_doc(), "Courier");
Tom Sepez20c41a52018-08-29 23:53:53 +00002910 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2911 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2912 FPDF_FONT_TRUETYPE, false));
Nicolas Penab3161852017-05-02 14:12:50 -04002913 ASSERT_TRUE(font.get());
Tom Sepez525147a2018-05-03 17:19:53 +00002914 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -05002915 EXPECT_TRUE(typed_font->IsTrueTypeFont());
Nicolas Penabe90aae2017-02-27 10:41:41 -05002916
Lei Zhang710fa992018-05-25 16:24:48 +00002917 const CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Lei Zhanga228ff32020-06-24 17:39:33 +00002918 EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
2919 EXPECT_EQ("TrueType", font_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00002920 EXPECT_EQ("Cousine-Regular", font_dict->GetNameFor("BaseFont"));
Nicolas Penad03ca422017-03-06 13:54:33 -05002921 ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
2922 ASSERT_TRUE(font_dict->KeyExist("LastChar"));
2923 EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
2924 EXPECT_EQ(255, font_dict->GetIntegerFor("LastChar"));
Nicolas Penabe90aae2017-02-27 10:41:41 -05002925
Lei Zhangde579ab2018-05-25 21:49:49 +00002926 const CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
Nicolas Penad03ca422017-03-06 13:54:33 -05002927 ASSERT_TRUE(widths_array);
Lei Zhangf40380f2018-10-12 18:31:51 +00002928 ASSERT_EQ(224u, widths_array->size());
Nicolas Penad03ca422017-03-06 13:54:33 -05002929 EXPECT_EQ(600, widths_array->GetNumberAt(33));
2930 EXPECT_EQ(600, widths_array->GetNumberAt(74));
2931 EXPECT_EQ(600, widths_array->GetNumberAt(223));
Tom Sepez20c41a52018-08-29 23:53:53 +00002932 CheckFontDescriptor(font_dict, FPDF_FONT_TRUETYPE, false, false, span);
Nicolas Penad03ca422017-03-06 13:54:33 -05002933}
2934
Lei Zhangab41f252018-12-23 03:10:50 +00002935TEST_F(FPDFEditEmbedderTest, LoadCIDType0Font) {
Nicolas Penad03ca422017-03-06 13:54:33 -05002936 CreateNewDocument();
Tom Sepezffff6c52019-07-30 21:56:19 +00002937 RetainPtr<CPDF_Font> stock_font =
Nicolas Penad03ca422017-03-06 13:54:33 -05002938 CPDF_Font::GetStockFont(cpdf_doc(), "Times-Roman");
Tom Sepez20c41a52018-08-29 23:53:53 +00002939 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2940 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2941 FPDF_FONT_TYPE1, 1));
Nicolas Penab3161852017-05-02 14:12:50 -04002942 ASSERT_TRUE(font.get());
Tom Sepez525147a2018-05-03 17:19:53 +00002943 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -05002944 EXPECT_TRUE(typed_font->IsCIDFont());
2945
2946 // Check font dictionary entries
Lei Zhang710fa992018-05-25 16:24:48 +00002947 const CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Lei Zhanga228ff32020-06-24 17:39:33 +00002948 EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
2949 EXPECT_EQ("Type0", font_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00002950 EXPECT_EQ("Tinos-Regular-Identity-H", font_dict->GetNameFor("BaseFont"));
Lei Zhanga228ff32020-06-24 17:39:33 +00002951 EXPECT_EQ("Identity-H", font_dict->GetNameFor("Encoding"));
Lei Zhangde579ab2018-05-25 21:49:49 +00002952 const CPDF_Array* descendant_array =
2953 font_dict->GetArrayFor("DescendantFonts");
Nicolas Penad03ca422017-03-06 13:54:33 -05002954 ASSERT_TRUE(descendant_array);
Lei Zhangf40380f2018-10-12 18:31:51 +00002955 EXPECT_EQ(1u, descendant_array->size());
Nicolas Penad03ca422017-03-06 13:54:33 -05002956
2957 // Check the CIDFontDict
Lei Zhangde579ab2018-05-25 21:49:49 +00002958 const CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
Lei Zhanga228ff32020-06-24 17:39:33 +00002959 EXPECT_EQ("Font", cidfont_dict->GetNameFor("Type"));
2960 EXPECT_EQ("CIDFontType0", cidfont_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00002961 EXPECT_EQ("Tinos-Regular", cidfont_dict->GetNameFor("BaseFont"));
Lei Zhangb1ec2802018-05-25 21:55:24 +00002962 const CPDF_Dictionary* cidinfo_dict =
2963 cidfont_dict->GetDictFor("CIDSystemInfo");
Nicolas Penad03ca422017-03-06 13:54:33 -05002964 ASSERT_TRUE(cidinfo_dict);
Lei Zhang9c950b12019-01-16 19:06:37 +00002965 const CPDF_Object* registry = cidinfo_dict->GetObjectFor("Registry");
2966 ASSERT_TRUE(registry);
KDr28da0e1b2019-01-17 03:44:29 +00002967 EXPECT_EQ(CPDF_Object::kString, registry->GetType());
Lei Zhang9c950b12019-01-16 19:06:37 +00002968 EXPECT_EQ("Adobe", registry->GetString());
2969 const CPDF_Object* ordering = cidinfo_dict->GetObjectFor("Ordering");
2970 ASSERT_TRUE(ordering);
KDr28da0e1b2019-01-17 03:44:29 +00002971 EXPECT_EQ(CPDF_Object::kString, ordering->GetType());
Lei Zhang9c950b12019-01-16 19:06:37 +00002972 EXPECT_EQ("Identity", ordering->GetString());
Nicolas Penad03ca422017-03-06 13:54:33 -05002973 EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
Tom Sepez20c41a52018-08-29 23:53:53 +00002974 CheckFontDescriptor(cidfont_dict, FPDF_FONT_TYPE1, false, false, span);
Nicolas Penad03ca422017-03-06 13:54:33 -05002975
2976 // Check widths
Lei Zhangde579ab2018-05-25 21:49:49 +00002977 const CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
Nicolas Penad03ca422017-03-06 13:54:33 -05002978 ASSERT_TRUE(widths_array);
Lei Zhangf40380f2018-10-12 18:31:51 +00002979 EXPECT_GT(widths_array->size(), 1u);
Nicolas Penad03ca422017-03-06 13:54:33 -05002980 CheckCompositeFontWidths(widths_array, typed_font);
2981}
2982
Lei Zhangab41f252018-12-23 03:10:50 +00002983TEST_F(FPDFEditEmbedderTest, LoadCIDType2Font) {
Nicolas Penad03ca422017-03-06 13:54:33 -05002984 CreateNewDocument();
Tom Sepezffff6c52019-07-30 21:56:19 +00002985 RetainPtr<CPDF_Font> stock_font =
Nicolas Penad03ca422017-03-06 13:54:33 -05002986 CPDF_Font::GetStockFont(cpdf_doc(), "Helvetica-Oblique");
Tom Sepez20c41a52018-08-29 23:53:53 +00002987 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
2988 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
2989 FPDF_FONT_TRUETYPE, 1));
Nicolas Penab3161852017-05-02 14:12:50 -04002990 ASSERT_TRUE(font.get());
Tom Sepez525147a2018-05-03 17:19:53 +00002991 CPDF_Font* typed_font = CPDFFontFromFPDFFont(font.get());
Nicolas Penad03ca422017-03-06 13:54:33 -05002992 EXPECT_TRUE(typed_font->IsCIDFont());
2993
2994 // Check font dictionary entries
Lei Zhang710fa992018-05-25 16:24:48 +00002995 const CPDF_Dictionary* font_dict = typed_font->GetFontDict();
Lei Zhanga228ff32020-06-24 17:39:33 +00002996 EXPECT_EQ("Font", font_dict->GetNameFor("Type"));
2997 EXPECT_EQ("Type0", font_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00002998 EXPECT_EQ("Arimo-Italic", font_dict->GetNameFor("BaseFont"));
Lei Zhanga228ff32020-06-24 17:39:33 +00002999 EXPECT_EQ("Identity-H", font_dict->GetNameFor("Encoding"));
Lei Zhangde579ab2018-05-25 21:49:49 +00003000 const CPDF_Array* descendant_array =
3001 font_dict->GetArrayFor("DescendantFonts");
Nicolas Penad03ca422017-03-06 13:54:33 -05003002 ASSERT_TRUE(descendant_array);
Lei Zhangf40380f2018-10-12 18:31:51 +00003003 EXPECT_EQ(1u, descendant_array->size());
Nicolas Penad03ca422017-03-06 13:54:33 -05003004
3005 // Check the CIDFontDict
Lei Zhangde579ab2018-05-25 21:49:49 +00003006 const CPDF_Dictionary* cidfont_dict = descendant_array->GetDictAt(0);
Lei Zhanga228ff32020-06-24 17:39:33 +00003007 EXPECT_EQ("Font", cidfont_dict->GetNameFor("Type"));
3008 EXPECT_EQ("CIDFontType2", cidfont_dict->GetNameFor("Subtype"));
Tom Andersond4fe5f72021-12-03 20:52:52 +00003009 EXPECT_EQ("Arimo-Italic", cidfont_dict->GetNameFor("BaseFont"));
Lei Zhangb1ec2802018-05-25 21:55:24 +00003010 const CPDF_Dictionary* cidinfo_dict =
3011 cidfont_dict->GetDictFor("CIDSystemInfo");
Nicolas Penad03ca422017-03-06 13:54:33 -05003012 ASSERT_TRUE(cidinfo_dict);
3013 EXPECT_EQ("Adobe", cidinfo_dict->GetStringFor("Registry"));
3014 EXPECT_EQ("Identity", cidinfo_dict->GetStringFor("Ordering"));
3015 EXPECT_EQ(0, cidinfo_dict->GetNumberFor("Supplement"));
Tom Sepez20c41a52018-08-29 23:53:53 +00003016 CheckFontDescriptor(cidfont_dict, FPDF_FONT_TRUETYPE, false, true, span);
Nicolas Penad03ca422017-03-06 13:54:33 -05003017
3018 // Check widths
Lei Zhangde579ab2018-05-25 21:49:49 +00003019 const CPDF_Array* widths_array = cidfont_dict->GetArrayFor("W");
Nicolas Penad03ca422017-03-06 13:54:33 -05003020 ASSERT_TRUE(widths_array);
3021 CheckCompositeFontWidths(widths_array, typed_font);
Nicolas Penabe90aae2017-02-27 10:41:41 -05003022}
rbpotterce8e51e2017-04-28 12:42:47 -07003023
Lei Zhangab41f252018-12-23 03:10:50 +00003024TEST_F(FPDFEditEmbedderTest, NormalizeNegativeRotation) {
rbpotterce8e51e2017-04-28 12:42:47 -07003025 // Load document with a -90 degree rotation
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003026 ASSERT_TRUE(OpenDocument("bug_713197.pdf"));
rbpotterce8e51e2017-04-28 12:42:47 -07003027 FPDF_PAGE page = LoadPage(0);
3028 EXPECT_NE(nullptr, page);
3029
3030 EXPECT_EQ(3, FPDFPage_GetRotation(page));
3031 UnloadPage(page);
3032}
Nicolas Penab3161852017-05-02 14:12:50 -04003033
Hui Yingst9d6ec8f2020-11-05 23:35:38 +00003034TEST_F(FPDFEditEmbedderTest, AddTrueTypeFontText) {
Nicolas Penab3161852017-05-02 14:12:50 -04003035 // Start with a blank page
3036 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
3037 {
Tom Sepezffff6c52019-07-30 21:56:19 +00003038 RetainPtr<CPDF_Font> stock_font =
3039 CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
Tom Sepez20c41a52018-08-29 23:53:53 +00003040 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
3041 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3042 FPDF_FONT_TRUETYPE, 0));
Nicolas Penab3161852017-05-02 14:12:50 -04003043 ASSERT_TRUE(font.get());
3044
3045 // Add some text to the page
3046 FPDF_PAGEOBJECT text_object =
3047 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
3048 EXPECT_TRUE(text_object);
Hui Yingst3b6136a2020-06-09 00:39:33 +00003049 ScopedFPDFWideString text = GetFPDFWideString(kLoadedFontText);
Nicolas Penab3161852017-05-02 14:12:50 -04003050 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
3051 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
3052 FPDFPage_InsertObject(page, text_object);
Lei Zhang30ff2532019-01-31 21:37:55 +00003053 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst3b6136a2020-06-09 00:39:33 +00003054 CompareBitmap(page_bitmap.get(), 612, 792, kLoadedFontTextChecksum);
Nicolas Penab3161852017-05-02 14:12:50 -04003055
3056 // Add some more text, same font
3057 FPDF_PAGEOBJECT text_object2 =
3058 FPDFPageObj_CreateTextObj(document(), font.get(), 15.0f);
Lei Zhangf0f67682019-04-08 17:03:21 +00003059 ScopedFPDFWideString text2 = GetFPDFWideString(L"Bigger font size");
Nicolas Penab3161852017-05-02 14:12:50 -04003060 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
3061 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 200, 200);
3062 FPDFPage_InsertObject(page, text_object2);
Nicolas Penab3161852017-05-02 14:12:50 -04003063 }
Lei Zhang30ff2532019-01-31 21:37:55 +00003064 ScopedFPDFBitmap page_bitmap2 = RenderPage(page);
Hui Yingst9d6ec8f2020-11-05 23:35:38 +00003065#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
Hui Yingste1215fc2022-03-26 22:29:08 +00003066 const char kInsertTrueTypeChecksum[] = "683f4a385a891494100192cb338b11f0";
Lei Zhang42d30c22022-01-12 19:24:43 +00003067#elif BUILDFLAG(IS_APPLE)
Tom Andersond4fe5f72021-12-03 20:52:52 +00003068 const char kInsertTrueTypeChecksum[] = "c7e2271a7f30e5b919a13ead47cea105";
Nicolas Penab3161852017-05-02 14:12:50 -04003069#else
Tom Andersond4fe5f72021-12-03 20:52:52 +00003070 const char kInsertTrueTypeChecksum[] = "683f4a385a891494100192cb338b11f0";
Lei Zhange4cdac52019-04-30 16:45:57 +00003071#endif
Hui Yingst3b6136a2020-06-09 00:39:33 +00003072 CompareBitmap(page_bitmap2.get(), 612, 792, kInsertTrueTypeChecksum);
Nicolas Penab3161852017-05-02 14:12:50 -04003073
Nicolas Pena207b7272017-05-26 17:37:06 -04003074 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Nicolas Penab3161852017-05-02 14:12:50 -04003075 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3076 FPDF_ClosePage(page);
Dan Sinclair04e4dc82017-10-18 12:17:14 -04003077
Hui Yingst3b6136a2020-06-09 00:39:33 +00003078 VerifySavedDocument(612, 792, kInsertTrueTypeChecksum);
Nicolas Penab3161852017-05-02 14:12:50 -04003079}
Nicolas Penaf45ade32017-05-03 10:23:49 -04003080
Lei Zhangab41f252018-12-23 03:10:50 +00003081TEST_F(FPDFEditEmbedderTest, TransformAnnot) {
Jane Liueda65252017-06-07 11:31:27 -04003082 // Open a file with one annotation and load its first page.
3083 ASSERT_TRUE(OpenDocument("annotation_highlight_long_content.pdf"));
Lei Zhang75c81712018-02-08 17:22:39 +00003084 FPDF_PAGE page = LoadPage(0);
Jane Liueda65252017-06-07 11:31:27 -04003085 ASSERT_TRUE(page);
3086
Lei Zhanga21d5932018-02-05 18:28:38 +00003087 {
3088 // Add an underline annotation to the page without specifying its rectangle.
Tom Sepeze08d2b12018-04-25 18:49:32 +00003089 ScopedFPDFAnnotation annot(
Lei Zhanga21d5932018-02-05 18:28:38 +00003090 FPDFPage_CreateAnnot(page, FPDF_ANNOT_UNDERLINE));
3091 ASSERT_TRUE(annot);
Jane Liueda65252017-06-07 11:31:27 -04003092
Lei Zhanga21d5932018-02-05 18:28:38 +00003093 // FPDFPage_TransformAnnots() should run without errors when modifying
3094 // annotation rectangles.
3095 FPDFPage_TransformAnnots(page, 1, 2, 3, 4, 5, 6);
3096 }
Jane Liueda65252017-06-07 11:31:27 -04003097 UnloadPage(page);
3098}
3099
Nicolas Penaf45ade32017-05-03 10:23:49 -04003100// TODO(npm): Add tests using Japanese fonts in other OS.
Lei Zhangeb2da2a2022-01-12 19:28:33 +00003101#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
Hui Yingst5ce6a3f2020-11-11 02:29:09 +00003102TEST_F(FPDFEditEmbedderTest, AddCIDFontText) {
Nicolas Penaf45ade32017-05-03 10:23:49 -04003103 // Start with a blank page
3104 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
3105 CFX_Font CIDfont;
3106 {
3107 // First, get the data from the font
Anton Bikineev7ac13342022-01-24 21:25:15 +00003108 CIDfont.LoadSubst("Noto Sans CJK JP", true, 0, 400, 0,
3109 FX_CodePage::kShiftJIS, false);
Tom Andersond4fe5f72021-12-03 20:52:52 +00003110 EXPECT_EQ("Noto Sans CJK JP", CIDfont.GetFaceName());
Tom Sepez20c41a52018-08-29 23:53:53 +00003111 pdfium::span<const uint8_t> span = CIDfont.GetFontSpan();
Nicolas Penaf45ade32017-05-03 10:23:49 -04003112
3113 // Load the data into a FPDF_Font.
Tom Sepez20c41a52018-08-29 23:53:53 +00003114 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3115 FPDF_FONT_TRUETYPE, 1));
Nicolas Penaf45ade32017-05-03 10:23:49 -04003116 ASSERT_TRUE(font.get());
3117
3118 // Add some text to the page
3119 FPDF_PAGEOBJECT text_object =
3120 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
3121 ASSERT_TRUE(text_object);
3122 std::wstring wstr = L"ABCDEFGhijklmnop.";
Lei Zhangf0f67682019-04-08 17:03:21 +00003123 ScopedFPDFWideString text = GetFPDFWideString(wstr);
Nicolas Penaf45ade32017-05-03 10:23:49 -04003124 EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
3125 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 200, 200);
3126 FPDFPage_InsertObject(page, text_object);
3127
3128 // And add some Japanese characters
3129 FPDF_PAGEOBJECT text_object2 =
3130 FPDFPageObj_CreateTextObj(document(), font.get(), 18.0f);
3131 ASSERT_TRUE(text_object2);
3132 std::wstring wstr2 =
3133 L"\u3053\u3093\u306B\u3061\u306f\u4e16\u754C\u3002\u3053\u3053\u306B1"
3134 L"\u756A";
Lei Zhangf0f67682019-04-08 17:03:21 +00003135 ScopedFPDFWideString text2 = GetFPDFWideString(wstr2);
Nicolas Penaf45ade32017-05-03 10:23:49 -04003136 EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
3137 FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 500);
3138 FPDFPage_InsertObject(page, text_object2);
3139 }
3140
Nicolas Pena207b7272017-05-26 17:37:06 -04003141 // Check that the text renders properly.
Tom Andersond4fe5f72021-12-03 20:52:52 +00003142 static constexpr char md5[] = "84d31d11b76845423a2cfc1879c0fbb9";
Lei Zhang107fa7b2018-02-09 21:48:15 +00003143 {
Lei Zhang30ff2532019-01-31 21:37:55 +00003144 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Lei Zhang107fa7b2018-02-09 21:48:15 +00003145 CompareBitmap(page_bitmap.get(), 612, 792, md5);
3146 }
Nicolas Penaf45ade32017-05-03 10:23:49 -04003147
3148 // Save the document, close the page.
Nicolas Pena207b7272017-05-26 17:37:06 -04003149 EXPECT_TRUE(FPDFPage_GenerateContent(page));
Nicolas Penaf45ade32017-05-03 10:23:49 -04003150 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3151 FPDF_ClosePage(page);
Dan Sinclair04e4dc82017-10-18 12:17:14 -04003152
3153 VerifySavedDocument(612, 792, md5);
Nicolas Penaf45ade32017-05-03 10:23:49 -04003154}
Lei Zhangeb2da2a2022-01-12 19:28:33 +00003155#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003156
Hui Yingst29d377b2021-03-03 20:22:41 +00003157// TODO(crbug.com/pdfium/1651): Fix this issue and enable the test for Skia.
3158#if defined(_SKIA_SUPPORT_)
Lei Zhang03e5e682019-09-16 19:45:55 +00003159#define MAYBE_SaveAndRender DISABLED_SaveAndRender
3160#else
3161#define MAYBE_SaveAndRender SaveAndRender
3162#endif
3163TEST_F(FPDFEditEmbedderTest, MAYBE_SaveAndRender) {
Hui Yingst29d377b2021-03-03 20:22:41 +00003164#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
3165 static constexpr char kChecksum[] = "0e8b079e349e34f64211c495845a3529";
3166#else
3167 static constexpr char kChecksum[] = "3c20472b0552c0c22b88ab1ed8c6202b";
3168#endif
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003169 {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003170 ASSERT_TRUE(OpenDocument("bug_779.pdf"));
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003171 FPDF_PAGE page = LoadPage(0);
3172 ASSERT_NE(nullptr, page);
3173
Hui Yingst29d377b2021-03-03 20:22:41 +00003174 // Now add a more complex green path.
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003175 FPDF_PAGEOBJECT green_path = FPDFPageObj_CreateNewPath(20, 20);
Lei Zhang3475b482019-05-13 18:30:57 +00003176 EXPECT_TRUE(FPDFPageObj_SetFillColor(green_path, 0, 255, 0, 200));
Hui Yingst29d377b2021-03-03 20:22:41 +00003177 // TODO(npm): stroking will cause the checksums to differ.
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003178 EXPECT_TRUE(FPDFPath_SetDrawMode(green_path, FPDF_FILLMODE_WINDING, 0));
3179 EXPECT_TRUE(FPDFPath_LineTo(green_path, 20, 63));
3180 EXPECT_TRUE(FPDFPath_BezierTo(green_path, 55, 55, 78, 78, 90, 90));
3181 EXPECT_TRUE(FPDFPath_LineTo(green_path, 133, 133));
3182 EXPECT_TRUE(FPDFPath_LineTo(green_path, 133, 33));
3183 EXPECT_TRUE(FPDFPath_BezierTo(green_path, 38, 33, 39, 36, 40, 40));
3184 EXPECT_TRUE(FPDFPath_Close(green_path));
3185 FPDFPage_InsertObject(page, green_path);
Tom Sepeze08d2b12018-04-25 18:49:32 +00003186 ScopedFPDFBitmap page_bitmap = RenderLoadedPage(page);
Hui Yingst29d377b2021-03-03 20:22:41 +00003187 CompareBitmap(page_bitmap.get(), 612, 792, kChecksum);
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003188
3189 // Now save the result, closing the page and document
3190 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3191 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3192 UnloadPage(page);
3193 }
Dan Sinclair04e4dc82017-10-18 12:17:14 -04003194
Hui Yingst29d377b2021-03-03 20:22:41 +00003195 VerifySavedDocument(612, 792, kChecksum);
Nicolas Pena9ba8fbc2017-06-28 15:31:56 -04003196}
Jane Liu28fb7ba2017-08-02 21:45:57 -04003197
Lei Zhangab41f252018-12-23 03:10:50 +00003198TEST_F(FPDFEditEmbedderTest, AddMark) {
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003199 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003200 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003201 FPDF_PAGE page = LoadPage(0);
3202 ASSERT_TRUE(page);
3203
Lei Zhang2697cb12019-07-03 18:14:29 +00003204 CheckMarkCounts(page, 1, 19, 8, 4, 9, 1);
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003205
3206 // Add to the first page object a "Bounds" mark with "Position": "First".
3207 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
3208 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(page_object, "Bounds");
3209 EXPECT_TRUE(mark);
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003210 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
3211 "Position", "First"));
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003212
Lei Zhang2697cb12019-07-03 18:14:29 +00003213 CheckMarkCounts(page, 1, 19, 8, 4, 9, 2);
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003214
3215 // Save the file
3216 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3217 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3218 UnloadPage(page);
3219
3220 // Re-open the file and check the new mark is present.
Lei Zhang0b494052019-01-31 21:41:15 +00003221 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003222 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00003223 ASSERT_TRUE(saved_page);
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003224
Lei Zhang2697cb12019-07-03 18:14:29 +00003225 CheckMarkCounts(saved_page, 1, 19, 8, 4, 9, 2);
3226
3227 CloseSavedPage(saved_page);
3228 CloseSavedDocument();
3229}
3230
Hui Yingst04440af2020-07-27 22:39:02 +00003231TEST_F(FPDFEditEmbedderTest, AddMarkCompressedStream) {
Lei Zhang2697cb12019-07-03 18:14:29 +00003232 // Load document with some text in a compressed stream.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003233 ASSERT_TRUE(OpenDocument("hello_world_compressed_stream.pdf"));
Lei Zhang2697cb12019-07-03 18:14:29 +00003234 FPDF_PAGE page = LoadPage(0);
3235 ASSERT_TRUE(page);
3236
3237 // Render and check there are no marks.
3238 {
3239 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00003240 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Lei Zhang2697cb12019-07-03 18:14:29 +00003241 }
3242 CheckMarkCounts(page, 0, 2, 0, 0, 0, 0);
3243
3244 // Add to the first page object a "Bounds" mark with "Position": "First".
3245 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
3246 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(page_object, "Bounds");
3247 EXPECT_TRUE(mark);
3248 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
3249 "Position", "First"));
3250
3251 // Render and check there is 1 mark.
3252 {
3253 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00003254 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Lei Zhang2697cb12019-07-03 18:14:29 +00003255 }
3256 CheckMarkCounts(page, 0, 2, 0, 0, 0, 1);
3257
3258 // Save the file.
3259 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3260 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3261 UnloadPage(page);
3262
3263 // Re-open the file and check the new mark is present.
3264 ASSERT_TRUE(OpenSavedDocument());
3265 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00003266 ASSERT_TRUE(saved_page);
Lei Zhang2697cb12019-07-03 18:14:29 +00003267
3268 {
3269 ScopedFPDFBitmap page_bitmap = RenderPage(saved_page);
Hui Yingstb4baceb2020-04-28 23:46:10 +00003270 CompareBitmap(page_bitmap.get(), 200, 200, kHelloWorldChecksum);
Lei Zhang2697cb12019-07-03 18:14:29 +00003271 }
3272 CheckMarkCounts(saved_page, 0, 2, 0, 0, 0, 1);
Henrique Nakashimad8df8c32018-07-12 22:15:09 +00003273
3274 CloseSavedPage(saved_page);
3275 CloseSavedDocument();
3276}
3277
Lei Zhangab41f252018-12-23 03:10:50 +00003278TEST_F(FPDFEditEmbedderTest, SetMarkParam) {
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003279 // Load document with some text.
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003280 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003281 FPDF_PAGE page = LoadPage(0);
3282 ASSERT_TRUE(page);
3283
3284 constexpr int kExpectedObjectCount = 19;
3285 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
3286
3287 // Check the "Bounds" mark's "Position" param is "Last".
3288 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3289 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3290 ASSERT_TRUE(mark);
3291 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003292 unsigned long name_len = 999u;
3293 ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
3294 EXPECT_EQ((6u + 1u) * 2u, name_len);
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003295 ASSERT_EQ(L"Bounds",
3296 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3297 unsigned long out_buffer_len;
3298 ASSERT_TRUE(FPDFPageObjMark_GetParamStringValue(
3299 mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
3300 ASSERT_EQ(L"Last",
3301 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3302
3303 // Set is to "End".
3304 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), page_object, mark,
3305 "Position", "End"));
3306
3307 // Verify the object passed must correspond to the mark passed.
3308 FPDF_PAGEOBJECT another_page_object = FPDFPage_GetObject(page, 17);
3309 EXPECT_FALSE(FPDFPageObjMark_SetStringParam(document(), another_page_object,
3310 mark, "Position", "End"));
3311
3312 // Verify nothing else changed.
3313 CheckMarkCounts(page, 1, kExpectedObjectCount, 8, 4, 9, 1);
3314
3315 // Verify "Position" now maps to "End".
3316 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
3317 mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
3318 EXPECT_EQ(L"End",
3319 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3320
3321 // Save the file
3322 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3323 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3324 UnloadPage(page);
3325
3326 // Re-open the file and cerify "Position" still maps to "End".
Lei Zhang0b494052019-01-31 21:41:15 +00003327 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003328 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00003329 ASSERT_TRUE(saved_page);
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003330
3331 CheckMarkCounts(saved_page, 1, kExpectedObjectCount, 8, 4, 9, 1);
3332 page_object = FPDFPage_GetObject(saved_page, 18);
3333 mark = FPDFPageObj_GetMark(page_object, 1);
3334 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
3335 mark, "Position", buffer, sizeof(buffer), &out_buffer_len));
3336 EXPECT_EQ(L"End",
3337 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3338
3339 CloseSavedPage(saved_page);
3340 CloseSavedDocument();
3341}
3342
Hui Yingst9d6ec8f2020-11-05 23:35:38 +00003343TEST_F(FPDFEditEmbedderTest, AddMarkedText) {
Henrique Nakashima144107d2018-07-10 21:04:05 +00003344 // Start with a blank page.
3345 FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
3346
Tom Sepezffff6c52019-07-30 21:56:19 +00003347 RetainPtr<CPDF_Font> stock_font =
3348 CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
Tom Sepez20c41a52018-08-29 23:53:53 +00003349 pdfium::span<const uint8_t> span = stock_font->GetFont()->GetFontSpan();
3350 ScopedFPDFFont font(FPDFText_LoadFont(document(), span.data(), span.size(),
3351 FPDF_FONT_TRUETYPE, 0));
Henrique Nakashima144107d2018-07-10 21:04:05 +00003352 ASSERT_TRUE(font.get());
3353
3354 // Add some text to the page.
3355 FPDF_PAGEOBJECT text_object =
3356 FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
3357
3358 EXPECT_TRUE(text_object);
Hui Yingst3b6136a2020-06-09 00:39:33 +00003359 ScopedFPDFWideString text1 = GetFPDFWideString(kLoadedFontText);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003360 EXPECT_TRUE(FPDFText_SetText(text_object, text1.get()));
3361 FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
3362 FPDFPage_InsertObject(page, text_object);
3363
3364 // Add a mark with the tag "TestMarkName" to that text.
3365 EXPECT_EQ(0, FPDFPageObj_CountMarks(text_object));
Henrique Nakashima6fc8d872018-09-18 16:48:31 +00003366 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_AddMark(text_object, "Test Mark Name");
Henrique Nakashima144107d2018-07-10 21:04:05 +00003367 EXPECT_TRUE(mark);
3368 EXPECT_EQ(1, FPDFPageObj_CountMarks(text_object));
3369 EXPECT_EQ(mark, FPDFPageObj_GetMark(text_object, 0));
3370 char buffer[256];
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003371 unsigned long name_len = 999u;
3372 ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
3373 EXPECT_EQ((14u + 1u) * 2, name_len);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003374 std::wstring name =
3375 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
Henrique Nakashima6fc8d872018-09-18 16:48:31 +00003376 EXPECT_EQ(L"Test Mark Name", name);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003377
3378 // Add parameters:
3379 // - int "IntKey" : 42
3380 // - string "StringKey": "StringValue"
Henrique Nakashima07520f62018-07-12 19:45:29 +00003381 // - blob "BlobKey": "\x01\x02\x03\0BlobValue1\0\0\0BlobValue2\0"
Lei Zhang590f4242019-05-15 20:57:26 +00003382 constexpr size_t kBlobLen = 28;
Lei Zhangd3b028b2018-11-30 22:22:00 +00003383 char block_value[kBlobLen];
3384 memcpy(block_value, "\x01\x02\x03\0BlobValue1\0\0\0BlobValue2\0", kBlobLen);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003385 EXPECT_EQ(0, FPDFPageObjMark_CountParams(mark));
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003386 EXPECT_TRUE(
3387 FPDFPageObjMark_SetIntParam(document(), text_object, mark, "IntKey", 42));
3388 EXPECT_TRUE(FPDFPageObjMark_SetStringParam(document(), text_object, mark,
3389 "StringKey", "StringValue"));
3390 EXPECT_TRUE(FPDFPageObjMark_SetBlobParam(document(), text_object, mark,
Lei Zhangd3b028b2018-11-30 22:22:00 +00003391 "BlobKey", block_value, kBlobLen));
Henrique Nakashima07520f62018-07-12 19:45:29 +00003392 EXPECT_EQ(3, FPDFPageObjMark_CountParams(mark));
Henrique Nakashima144107d2018-07-10 21:04:05 +00003393
3394 // Check the two parameters can be retrieved.
3395 EXPECT_EQ(FPDF_OBJECT_NUMBER,
Henrique Nakashima94230e52018-07-11 22:02:02 +00003396 FPDFPageObjMark_GetParamValueType(mark, "IntKey"));
Henrique Nakashima144107d2018-07-10 21:04:05 +00003397 int int_value;
Henrique Nakashima94230e52018-07-11 22:02:02 +00003398 EXPECT_TRUE(FPDFPageObjMark_GetParamIntValue(mark, "IntKey", &int_value));
Henrique Nakashima144107d2018-07-10 21:04:05 +00003399 EXPECT_EQ(42, int_value);
3400
3401 EXPECT_EQ(FPDF_OBJECT_STRING,
Henrique Nakashima94230e52018-07-11 22:02:02 +00003402 FPDFPageObjMark_GetParamValueType(mark, "StringKey"));
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003403 unsigned long out_buffer_len = 999u;
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003404 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(
3405 mark, "StringKey", buffer, sizeof(buffer), &out_buffer_len));
Henrique Nakashima144107d2018-07-10 21:04:05 +00003406 EXPECT_GT(out_buffer_len, 0u);
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003407 EXPECT_NE(999u, out_buffer_len);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003408 name = GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
3409 EXPECT_EQ(L"StringValue", name);
3410
Henrique Nakashima07520f62018-07-12 19:45:29 +00003411 EXPECT_EQ(FPDF_OBJECT_STRING,
3412 FPDFPageObjMark_GetParamValueType(mark, "BlobKey"));
3413 out_buffer_len = 0;
Henrique Nakashimaa3406772018-07-13 19:10:53 +00003414 EXPECT_TRUE(FPDFPageObjMark_GetParamBlobValue(
3415 mark, "BlobKey", buffer, sizeof(buffer), &out_buffer_len));
Henrique Nakashima07520f62018-07-12 19:45:29 +00003416 EXPECT_EQ(kBlobLen, out_buffer_len);
Lei Zhangd3b028b2018-11-30 22:22:00 +00003417 EXPECT_EQ(0, memcmp(block_value, buffer, kBlobLen));
Henrique Nakashima07520f62018-07-12 19:45:29 +00003418
Lei Zhangf16376e2020-06-18 19:19:32 +00003419 // Render and check the bitmap is the expected one.
Henrique Nakashima144107d2018-07-10 21:04:05 +00003420 {
Lei Zhang30ff2532019-01-31 21:37:55 +00003421 ScopedFPDFBitmap page_bitmap = RenderPage(page);
Hui Yingst3b6136a2020-06-09 00:39:33 +00003422 CompareBitmap(page_bitmap.get(), 612, 792, kLoadedFontTextChecksum);
Henrique Nakashima144107d2018-07-10 21:04:05 +00003423 }
3424
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003425 // Now save the result.
3426 EXPECT_EQ(1, FPDFPage_CountObjects(page));
3427 EXPECT_TRUE(FPDFPage_GenerateContent(page));
3428 EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
3429
Henrique Nakashima144107d2018-07-10 21:04:05 +00003430 FPDF_ClosePage(page);
3431
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003432 // Re-open the file and check the changes were kept in the saved .pdf.
Lei Zhang0b494052019-01-31 21:41:15 +00003433 ASSERT_TRUE(OpenSavedDocument());
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003434 FPDF_PAGE saved_page = LoadSavedPage(0);
Lei Zhangec618142021-04-13 17:36:46 +00003435 ASSERT_TRUE(saved_page);
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003436 EXPECT_EQ(1, FPDFPage_CountObjects(saved_page));
3437
3438 text_object = FPDFPage_GetObject(saved_page, 0);
3439 EXPECT_TRUE(text_object);
3440 EXPECT_EQ(1, FPDFPageObj_CountMarks(text_object));
3441 mark = FPDFPageObj_GetMark(text_object, 0);
3442 EXPECT_TRUE(mark);
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003443
3444 name_len = 999u;
3445 ASSERT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &name_len));
3446 EXPECT_EQ((14u + 1u) * 2, name_len);
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003447 name = GetPlatformWString(reinterpret_cast<unsigned short*>(buffer));
Henrique Nakashima6fc8d872018-09-18 16:48:31 +00003448 EXPECT_EQ(L"Test Mark Name", name);
Henrique Nakashimab4bcf692018-07-11 21:19:22 +00003449
3450 CloseSavedPage(saved_page);
3451 CloseSavedDocument();
Henrique Nakashima144107d2018-07-10 21:04:05 +00003452}
3453
Lei Zhangab41f252018-12-23 03:10:50 +00003454TEST_F(FPDFEditEmbedderTest, MarkGetName) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003455 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003456 FPDF_PAGE page = LoadPage(0);
3457 ASSERT_TRUE(page);
3458 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3459 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3460 ASSERT_TRUE(mark);
3461
3462 char buffer[256];
3463 unsigned long out_len;
3464
3465 // Show the positive cases of FPDFPageObjMark_GetName.
3466 out_len = 999u;
3467 EXPECT_TRUE(FPDFPageObjMark_GetName(mark, nullptr, 0, &out_len));
3468 EXPECT_EQ((6u + 1u) * 2u, out_len);
3469
3470 out_len = 999u;
3471 EXPECT_TRUE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), &out_len));
3472 EXPECT_EQ(L"Bounds",
3473 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3474 EXPECT_EQ((6u + 1u) * 2u, out_len);
3475
3476 // Show the negative cases of FPDFPageObjMark_GetName.
3477 out_len = 999u;
3478 EXPECT_FALSE(
3479 FPDFPageObjMark_GetName(nullptr, buffer, sizeof(buffer), &out_len));
3480 EXPECT_EQ(999u, out_len);
3481
3482 EXPECT_FALSE(FPDFPageObjMark_GetName(mark, buffer, sizeof(buffer), nullptr));
3483
3484 UnloadPage(page);
3485}
3486
Lei Zhangab41f252018-12-23 03:10:50 +00003487TEST_F(FPDFEditEmbedderTest, MarkGetParamKey) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003488 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003489 FPDF_PAGE page = LoadPage(0);
3490 ASSERT_TRUE(page);
3491 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3492 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3493 ASSERT_TRUE(mark);
3494
3495 char buffer[256];
3496 unsigned long out_len;
3497
3498 // Show the positive cases of FPDFPageObjMark_GetParamKey.
3499 out_len = 999u;
3500 EXPECT_TRUE(FPDFPageObjMark_GetParamKey(mark, 0, nullptr, 0, &out_len));
3501 EXPECT_EQ((8u + 1u) * 2u, out_len);
3502
3503 out_len = 999u;
3504 EXPECT_TRUE(
3505 FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer), &out_len));
3506 EXPECT_EQ(L"Position",
3507 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3508 EXPECT_EQ((8u + 1u) * 2u, out_len);
3509
3510 // Show the negative cases of FPDFPageObjMark_GetParamKey.
3511 out_len = 999u;
3512 EXPECT_FALSE(FPDFPageObjMark_GetParamKey(nullptr, 0, buffer, sizeof(buffer),
3513 &out_len));
3514 EXPECT_EQ(999u, out_len);
3515
3516 out_len = 999u;
3517 EXPECT_FALSE(
3518 FPDFPageObjMark_GetParamKey(mark, 1, buffer, sizeof(buffer), &out_len));
3519 EXPECT_EQ(999u, out_len);
3520
3521 EXPECT_FALSE(
3522 FPDFPageObjMark_GetParamKey(mark, 0, buffer, sizeof(buffer), nullptr));
3523
3524 UnloadPage(page);
3525}
3526
Lei Zhangab41f252018-12-23 03:10:50 +00003527TEST_F(FPDFEditEmbedderTest, MarkGetIntParam) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003528 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003529 FPDF_PAGE page = LoadPage(0);
3530 ASSERT_TRUE(page);
3531 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 8);
3532 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 0);
3533 ASSERT_TRUE(mark);
3534
3535 int out_value;
3536
3537 // Show the positive cases of FPDFPageObjMark_GetParamIntValue.
3538 out_value = 999;
3539 EXPECT_TRUE(FPDFPageObjMark_GetParamIntValue(mark, "Factor", &out_value));
3540 EXPECT_EQ(3, out_value);
3541
3542 // Show the negative cases of FPDFPageObjMark_GetParamIntValue.
3543 out_value = 999;
3544 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(nullptr, "Factor", &out_value));
3545 EXPECT_EQ(999, out_value);
3546
3547 out_value = 999;
3548 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "ParamThatDoesNotExist",
3549 &out_value));
3550 EXPECT_EQ(999, out_value);
3551
3552 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "Factor", nullptr));
3553
3554 page_object = FPDFPage_GetObject(page, 18);
3555 mark = FPDFPageObj_GetMark(page_object, 1);
3556 out_value = 999;
3557 EXPECT_FALSE(FPDFPageObjMark_GetParamIntValue(mark, "Position", &out_value));
3558 EXPECT_EQ(999, out_value);
3559
3560 UnloadPage(page);
3561}
3562
Lei Zhangab41f252018-12-23 03:10:50 +00003563TEST_F(FPDFEditEmbedderTest, MarkGetStringParam) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003564 ASSERT_TRUE(OpenDocument("text_in_page_marked.pdf"));
Henrique Nakashimac3099d12018-09-18 18:08:15 +00003565 FPDF_PAGE page = LoadPage(0);
3566 ASSERT_TRUE(page);
3567 FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 18);
3568 FPDF_PAGEOBJECTMARK mark = FPDFPageObj_GetMark(page_object, 1);
3569 ASSERT_TRUE(mark);
3570
3571 char buffer[256];
3572 unsigned long out_len;
3573
3574 // Show the positive cases of FPDFPageObjMark_GetParamStringValue.
3575 out_len = 999u;
3576 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(mark, "Position", nullptr, 0,
3577 &out_len));
3578 EXPECT_EQ((4u + 1u) * 2u, out_len);
3579
3580 out_len = 999u;
3581 EXPECT_TRUE(FPDFPageObjMark_GetParamStringValue(mark, "Position", buffer,
3582 sizeof(buffer), &out_len));
3583 EXPECT_EQ(L"Last",
3584 GetPlatformWString(reinterpret_cast<unsigned short*>(buffer)));
3585 EXPECT_EQ((4u + 1u) * 2u, out_len);
3586
3587 // Show the negative cases of FPDFPageObjMark_GetParamStringValue.
3588 out_len = 999u;
3589 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(nullptr, "Position", buffer,
3590 sizeof(buffer), &out_len));
3591 EXPECT_EQ(999u, out_len);
3592
3593 out_len = 999u;
3594 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(
3595 mark, "ParamThatDoesNotExist", buffer, sizeof(buffer), &out_len));
3596 EXPECT_EQ(999u, out_len);
3597
3598 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(mark, "Position", buffer,
3599 sizeof(buffer), nullptr));
3600
3601 page_object = FPDFPage_GetObject(page, 8);
3602 mark = FPDFPageObj_GetMark(page_object, 0);
3603 out_len = 999u;
3604 EXPECT_FALSE(FPDFPageObjMark_GetParamStringValue(mark, "Factor", buffer,
3605 sizeof(buffer), &out_len));
3606 EXPECT_EQ(999u, out_len);
3607
3608 UnloadPage(page);
3609}
3610
Lei Zhang2c57ad82022-02-04 02:21:28 +00003611// See also FPDFStructTreeEmbedderTest.GetMarkedContentID, which traverses the
3612// marked contents using FPDF_StructTree_GetForPage() and related API.
3613TEST_F(FPDFEditEmbedderTest, TraverseMarkedContentID) {
3614 ASSERT_TRUE(OpenDocument("marked_content_id.pdf"));
3615 FPDF_PAGE page = LoadPage(0);
3616 ASSERT_TRUE(page);
3617
3618 ASSERT_EQ(2, FPDFPage_CountObjects(page));
3619 FPDF_PAGEOBJECT object1 = FPDFPage_GetObject(page, 0);
3620 ASSERT_TRUE(object1);
3621 ASSERT_EQ(1, FPDFPageObj_CountMarks(object1));
3622
3623 FPDF_PAGEOBJECTMARK mark11 = FPDFPageObj_GetMark(object1, 0);
3624 ASSERT_TRUE(mark11);
3625 unsigned long len = 0;
3626 unsigned short buf[40];
3627 ASSERT_TRUE(FPDFPageObjMark_GetName(mark11, buf, sizeof(buf), &len));
3628 EXPECT_EQ(18u, len);
3629 EXPECT_EQ(L"Artifact", GetPlatformWString(buf));
3630 ASSERT_EQ(2, FPDFPageObjMark_CountParams(mark11));
3631 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark11, 0, buf, sizeof(buf), &len));
3632 EXPECT_EQ(10u, len);
3633 EXPECT_EQ(L"BBox", GetPlatformWString(buf));
3634 EXPECT_EQ(FPDF_OBJECT_ARRAY,
3635 FPDFPageObjMark_GetParamValueType(mark11, "BBox"));
3636 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark11, 1, buf, sizeof(buf), &len));
3637 EXPECT_EQ(10u, len);
3638 EXPECT_EQ(L"Type", GetPlatformWString(buf));
3639 EXPECT_EQ(FPDF_OBJECT_NAME,
3640 FPDFPageObjMark_GetParamValueType(mark11, "Type"));
3641
3642 FPDF_PAGEOBJECT object2 = FPDFPage_GetObject(page, 1);
3643 ASSERT_TRUE(object2);
3644 ASSERT_EQ(2, FPDFPageObj_CountMarks(object2));
3645 EXPECT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(object2));
3646
3647 FPDF_PAGEOBJECTMARK mark21 = FPDFPageObj_GetMark(object2, 0);
3648 ASSERT_TRUE(mark21);
3649 ASSERT_TRUE(FPDFPageObjMark_GetName(mark21, buf, sizeof(buf), &len));
3650 EXPECT_EQ(14u, len);
3651 EXPECT_EQ(L"Figure", GetPlatformWString(buf));
3652 ASSERT_EQ(1, FPDFPageObjMark_CountParams(mark21));
3653 ASSERT_TRUE(FPDFPageObjMark_GetParamKey(mark21, 0, buf, sizeof(buf), &len));
3654 EXPECT_EQ(10u, len);
3655 EXPECT_EQ(L"MCID", GetPlatformWString(buf));
3656 ASSERT_EQ(FPDF_OBJECT_NUMBER,
3657 FPDFPageObjMark_GetParamValueType(mark21, "MCID"));
3658 int mcid = -1;
3659 ASSERT_TRUE(FPDFPageObjMark_GetParamIntValue(mark21, "MCID", &mcid));
3660 EXPECT_EQ(0, mcid);
3661
3662 FPDF_PAGEOBJECTMARK mark22 = FPDFPageObj_GetMark(object2, 1);
3663 ASSERT_TRUE(mark22);
3664 ASSERT_TRUE(FPDFPageObjMark_GetName(mark22, buf, sizeof(buf), &len));
3665 EXPECT_EQ(18u, len);
3666 EXPECT_EQ(L"ClipSpan", GetPlatformWString(buf));
3667 EXPECT_EQ(0, FPDFPageObjMark_CountParams(mark22));
3668
3669 UnloadPage(page);
3670}
3671
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003672TEST_F(FPDFEditEmbedderTest, GetBitmap) {
Jane Liu28fb7ba2017-08-02 21:45:57 -04003673 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3674 FPDF_PAGE page = LoadPage(0);
3675 ASSERT_TRUE(page);
Miklos Vajna92627612017-09-25 12:59:29 +02003676 ASSERT_EQ(39, FPDFPage_CountObjects(page));
Jane Liu28fb7ba2017-08-02 21:45:57 -04003677
3678 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 32);
3679 EXPECT_NE(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3680 EXPECT_FALSE(FPDFImageObj_GetBitmap(obj));
3681
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003682 {
3683 obj = FPDFPage_GetObject(page, 33);
3684 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3685 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3686 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
Lei Zhang85166512020-07-14 23:28:56 +00003687 CompareBitmap(bitmap.get(), 109, 88, kEmbeddedImage33Checksum);
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003688 }
Jane Liu28fb7ba2017-08-02 21:45:57 -04003689
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003690 {
3691 obj = FPDFPage_GetObject(page, 34);
3692 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3693 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3694 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3695 CompareBitmap(bitmap.get(), 103, 75, "c8d51fa6821ceb2a67f08446ff236c40");
3696 }
Jane Liu28fb7ba2017-08-02 21:45:57 -04003697
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003698 {
3699 obj = FPDFPage_GetObject(page, 35);
3700 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3701 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3702 EXPECT_EQ(FPDFBitmap_Gray, FPDFBitmap_GetFormat(bitmap.get()));
3703 CompareBitmap(bitmap.get(), 92, 68, "9c6d76cb1e37ef8514f9455d759391f3");
3704 }
Jane Liu28fb7ba2017-08-02 21:45:57 -04003705
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003706 {
3707 obj = FPDFPage_GetObject(page, 36);
3708 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3709 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3710 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3711 CompareBitmap(bitmap.get(), 79, 60, "f4e72fb783a01c7b4614cdc25eaa98ac");
3712 }
Jane Liu28fb7ba2017-08-02 21:45:57 -04003713
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003714 {
3715 obj = FPDFPage_GetObject(page, 37);
3716 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3717 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3718 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3719 CompareBitmap(bitmap.get(), 126, 106, "2cf9e66414c72461f4ccbf9cdebdfa1b");
3720 }
Jane Liu28fb7ba2017-08-02 21:45:57 -04003721
Lei Zhang89ebf5c2020-07-14 20:59:05 +00003722 {
3723 obj = FPDFPage_GetObject(page, 38);
3724 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3725 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3726 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3727 CompareBitmap(bitmap.get(), 194, 119, "a8f3a126cec274dab8242fd2ccdc1b8b");
3728 }
3729
Jane Liu28fb7ba2017-08-02 21:45:57 -04003730 UnloadPage(page);
3731}
Jane Liu548334e2017-08-03 16:33:40 -04003732
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003733TEST_F(FPDFEditEmbedderTest, GetBitmapIgnoresSetMatrix) {
Lei Zhang85166512020-07-14 23:28:56 +00003734 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3735 FPDF_PAGE page = LoadPage(0);
3736 ASSERT_TRUE(page);
3737 ASSERT_EQ(39, FPDFPage_CountObjects(page));
3738
3739 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
3740 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3741
3742 {
3743 // Render |obj| as is.
3744 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3745 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3746 CompareBitmap(bitmap.get(), 109, 88, kEmbeddedImage33Checksum);
3747 }
3748
3749 // Check the matrix for |obj|.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003750 FS_MATRIX matrix;
3751 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3752 EXPECT_FLOAT_EQ(53.0f, matrix.a);
3753 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3754 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3755 EXPECT_FLOAT_EQ(43.0f, matrix.d);
3756 EXPECT_FLOAT_EQ(72.0f, matrix.e);
3757 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang85166512020-07-14 23:28:56 +00003758
3759 // Modify the matrix for |obj|.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003760 matrix.a = 120.0;
3761 EXPECT_TRUE(FPDFPageObj_SetMatrix(obj, &matrix));
Lei Zhang85166512020-07-14 23:28:56 +00003762
3763 // Make sure the matrix modification took place.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003764 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3765 EXPECT_FLOAT_EQ(120.0f, matrix.a);
3766 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3767 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3768 EXPECT_FLOAT_EQ(43.0f, matrix.d);
3769 EXPECT_FLOAT_EQ(72.0f, matrix.e);
3770 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang85166512020-07-14 23:28:56 +00003771
3772 {
Lei Zhangc8601bf2021-06-29 23:19:27 +00003773 // Render |obj| again. Note that the FPDFPageObj_SetMatrix() call has no
Lei Zhang85166512020-07-14 23:28:56 +00003774 // effect.
3775 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3776 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3777 CompareBitmap(bitmap.get(), 109, 88, kEmbeddedImage33Checksum);
3778 }
3779
3780 UnloadPage(page);
3781}
3782
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003783TEST_F(FPDFEditEmbedderTest, GetBitmapForJBigImage) {
Lei Zhang53341dd2018-03-01 15:42:47 +00003784 ASSERT_TRUE(OpenDocument("bug_631912.pdf"));
3785 FPDF_PAGE page = LoadPage(0);
3786 ASSERT_TRUE(page);
3787 ASSERT_EQ(1, FPDFPage_CountObjects(page));
3788
3789 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 0);
3790 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3791 {
Tom Sepeze08d2b12018-04-25 18:49:32 +00003792 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
Lei Zhang1330ebb2018-03-05 15:16:37 +00003793 ASSERT_TRUE(bitmap);
3794 EXPECT_EQ(FPDFBitmap_Gray, FPDFBitmap_GetFormat(bitmap.get()));
3795 CompareBitmap(bitmap.get(), 1152, 720, "3f6a48e2b3e91b799bf34567f55cb4de");
Lei Zhang53341dd2018-03-01 15:42:47 +00003796 }
3797
3798 UnloadPage(page);
3799}
3800
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003801TEST_F(FPDFEditEmbedderTest, GetBitmapIgnoresSMask) {
Lei Zhang2e1b4f22020-07-08 23:40:18 +00003802 ASSERT_TRUE(OpenDocument("matte.pdf"));
3803 FPDF_PAGE page = LoadPage(0);
3804 ASSERT_TRUE(page);
3805
3806 constexpr int kExpectedObjects = 4;
3807 ASSERT_EQ(kExpectedObjects, FPDFPage_CountObjects(page));
3808
3809 for (int i = 0; i < kExpectedObjects; ++i) {
3810 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, i);
3811 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3812 ScopedFPDFBitmap bitmap(FPDFImageObj_GetBitmap(obj));
3813 ASSERT_TRUE(bitmap);
3814 EXPECT_EQ(FPDFBitmap_BGR, FPDFBitmap_GetFormat(bitmap.get()));
3815 CompareBitmap(bitmap.get(), 50, 50, "46c9a1dbe0b44765ce46017ad629a2fe");
3816 }
3817
3818 UnloadPage(page);
3819}
3820
Hui Yingst822fb8d2020-10-05 22:10:35 +00003821// TODO(crbug.com/pdfium/11): Fix this test and enable.
3822#if defined(_SKIA_SUPPORT_)
3823#define MAYBE_GetRenderedBitmapHandlesSetMatrix \
3824 DISABLED_GetRenderedBitmapHandlesSetMatrix
3825#else
3826#define MAYBE_GetRenderedBitmapHandlesSetMatrix \
3827 GetRenderedBitmapHandlesSetMatrix
3828#endif
3829TEST_F(FPDFEditEmbedderTest, MAYBE_GetRenderedBitmapHandlesSetMatrix) {
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003830 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3831 FPDF_PAGE page = LoadPage(0);
3832 ASSERT_TRUE(page);
3833 ASSERT_EQ(39, FPDFPage_CountObjects(page));
3834
3835 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
3836 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3837
3838 {
3839 // Render |obj| as is.
3840 ScopedFPDFBitmap bitmap(
3841 FPDFImageObj_GetRenderedBitmap(document(), page, obj));
3842 EXPECT_EQ(FPDFBitmap_BGRA, FPDFBitmap_GetFormat(bitmap.get()));
Tom Sepezd661dc72021-06-24 20:22:19 +00003843 CompareBitmap(bitmap.get(), 53, 43, "582ca300e003f512d7b552c7b5b45d2e");
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003844 }
3845
3846 // Check the matrix for |obj|.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003847 FS_MATRIX matrix;
3848 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3849 EXPECT_FLOAT_EQ(53.0f, matrix.a);
3850 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3851 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3852 EXPECT_FLOAT_EQ(43.0f, matrix.d);
3853 EXPECT_FLOAT_EQ(72.0f, matrix.e);
3854 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003855
3856 // Modify the matrix for |obj|.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003857 matrix.a = 120.0;
3858 EXPECT_TRUE(FPDFPageObj_SetMatrix(obj, &matrix));
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003859
3860 // Make sure the matrix modification took place.
Lei Zhangc8601bf2021-06-29 23:19:27 +00003861 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3862 EXPECT_FLOAT_EQ(120.0f, matrix.a);
3863 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3864 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3865 EXPECT_FLOAT_EQ(43.0f, matrix.d);
3866 EXPECT_FLOAT_EQ(72.0f, matrix.e);
3867 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003868
3869 {
Lei Zhangc8601bf2021-06-29 23:19:27 +00003870 // Render |obj| again. Note that the FPDFPageObj_SetMatrix() call has an
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003871 // effect.
3872 ScopedFPDFBitmap bitmap(
3873 FPDFImageObj_GetRenderedBitmap(document(), page, obj));
3874 EXPECT_EQ(FPDFBitmap_BGRA, FPDFBitmap_GetFormat(bitmap.get()));
Tom Sepezd661dc72021-06-24 20:22:19 +00003875 CompareBitmap(bitmap.get(), 120, 43, "0824c16dcf2dfcef44b45d88db1fddce");
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003876 }
3877
3878 UnloadPage(page);
3879}
3880
Hui Yingst822fb8d2020-10-05 22:10:35 +00003881// TODO(crbug.com/pdfium/11): Fix this test and enable.
3882#if defined(_SKIA_SUPPORT_)
3883#define MAYBE_GetRenderedBitmapHandlesSMask \
3884 DISABLED_GetRenderedBitmapHandlesSMask
3885#else
3886#define MAYBE_GetRenderedBitmapHandlesSMask GetRenderedBitmapHandlesSMask
3887#endif
3888TEST_F(FPDFEditEmbedderTest, MAYBE_GetRenderedBitmapHandlesSMask) {
Lei Zhang0ac7b4e2020-07-18 00:35:53 +00003889 ASSERT_TRUE(OpenDocument("matte.pdf"));
3890 FPDF_PAGE page = LoadPage(0);
3891 ASSERT_TRUE(page);
3892
3893 constexpr int kExpectedObjects = 4;
3894 ASSERT_EQ(kExpectedObjects, FPDFPage_CountObjects(page));
3895
3896 for (int i = 0; i < kExpectedObjects; ++i) {
3897 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, i);
3898 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3899 ScopedFPDFBitmap bitmap(
3900 FPDFImageObj_GetRenderedBitmap(document(), page, obj));
3901 ASSERT_TRUE(bitmap);
3902 EXPECT_EQ(FPDFBitmap_BGRA, FPDFBitmap_GetFormat(bitmap.get()));
3903 if (i == 0)
3904 CompareBitmap(bitmap.get(), 40, 60, "5a3ae4a660ce919e29c42ec2258142f1");
3905 else
3906 CompareBitmap(bitmap.get(), 40, 60, "67504e83f5d78214ea00efc19082c5c1");
3907 }
3908
3909 UnloadPage(page);
3910}
3911
3912TEST_F(FPDFEditEmbedderTest, GetRenderedBitmapBadParams) {
3913 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3914 FPDF_PAGE page = LoadPage(0);
3915 ASSERT_TRUE(page);
3916
3917 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
3918 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3919
3920 // Test various null parameters.
3921 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, nullptr, nullptr));
3922 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(document(), nullptr, nullptr));
3923 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, page, nullptr));
3924 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, nullptr, obj));
3925 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(document(), page, nullptr));
3926 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(nullptr, page, obj));
3927
3928 // Test mismatch between document and page parameters.
3929 ScopedFPDFDocument new_document(FPDF_CreateNewDocument());
3930 EXPECT_FALSE(FPDFImageObj_GetRenderedBitmap(new_document.get(), page, obj));
3931
3932 UnloadPage(page);
3933}
3934
Lei Zhangab41f252018-12-23 03:10:50 +00003935TEST_F(FPDFEditEmbedderTest, GetImageData) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00003936 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
Jane Liu548334e2017-08-03 16:33:40 -04003937 FPDF_PAGE page = LoadPage(0);
3938 ASSERT_TRUE(page);
Miklos Vajna92627612017-09-25 12:59:29 +02003939 ASSERT_EQ(39, FPDFPage_CountObjects(page));
Jane Liu548334e2017-08-03 16:33:40 -04003940
3941 // Retrieve an image object with flate-encoded data stream.
3942 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 33);
3943 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3944
3945 // Check that the raw image data has the correct length and hash value.
3946 unsigned long len = FPDFImageObj_GetImageDataRaw(obj, nullptr, 0);
Lei Zhang0bd11f72022-05-11 00:10:54 +00003947 std::vector<uint8_t> buf(len);
Jane Liu548334e2017-08-03 16:33:40 -04003948 EXPECT_EQ(4091u, FPDFImageObj_GetImageDataRaw(obj, buf.data(), len));
Lei Zhang0bd11f72022-05-11 00:10:54 +00003949 EXPECT_EQ("f73802327d2e88e890f653961bcda81a", GenerateMD5Base16(buf));
Jane Liu548334e2017-08-03 16:33:40 -04003950
3951 // Check that the decoded image data has the correct length and hash value.
3952 len = FPDFImageObj_GetImageDataDecoded(obj, nullptr, 0);
3953 buf.clear();
3954 buf.resize(len);
3955 EXPECT_EQ(28776u, FPDFImageObj_GetImageDataDecoded(obj, buf.data(), len));
Lei Zhang0bd11f72022-05-11 00:10:54 +00003956 EXPECT_EQ(kEmbeddedImage33Checksum, GenerateMD5Base16(buf));
Jane Liu548334e2017-08-03 16:33:40 -04003957
Lei Zhang351e8b02018-12-20 01:10:06 +00003958 // Retrieve an image object with DCTDecode-encoded data stream.
Jane Liu548334e2017-08-03 16:33:40 -04003959 obj = FPDFPage_GetObject(page, 37);
3960 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
3961
3962 // Check that the raw image data has the correct length and hash value.
3963 len = FPDFImageObj_GetImageDataRaw(obj, nullptr, 0);
3964 buf.clear();
3965 buf.resize(len);
3966 EXPECT_EQ(4370u, FPDFImageObj_GetImageDataRaw(obj, buf.data(), len));
Lei Zhang0bd11f72022-05-11 00:10:54 +00003967 EXPECT_EQ("6aae1f3710335023a9e12191be66b64b", GenerateMD5Base16(buf));
Jane Liu548334e2017-08-03 16:33:40 -04003968
3969 // Check that the decoded image data has the correct length and hash value,
3970 // which should be the same as those of the raw data, since this image is
3971 // encoded by a single DCTDecode filter and decoding is a noop.
3972 len = FPDFImageObj_GetImageDataDecoded(obj, nullptr, 0);
3973 buf.clear();
3974 buf.resize(len);
3975 EXPECT_EQ(4370u, FPDFImageObj_GetImageDataDecoded(obj, buf.data(), len));
Lei Zhang0bd11f72022-05-11 00:10:54 +00003976 EXPECT_EQ("6aae1f3710335023a9e12191be66b64b", GenerateMD5Base16(buf));
Jane Liu548334e2017-08-03 16:33:40 -04003977
3978 UnloadPage(page);
3979}
Jane Liu2e5f0ae2017-08-08 15:23:27 -04003980
Lei Zhangab41f252018-12-23 03:10:50 +00003981TEST_F(FPDFEditEmbedderTest, GetImageMatrix) {
Lei Zhang866d6882018-10-24 17:31:01 +00003982 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
3983 FPDF_PAGE page = LoadPage(0);
3984 ASSERT_TRUE(page);
3985 ASSERT_EQ(39, FPDFPage_CountObjects(page));
3986
3987 FPDF_PAGEOBJECT obj;
Lei Zhangc8601bf2021-06-29 23:19:27 +00003988 FS_MATRIX matrix;
Lei Zhang866d6882018-10-24 17:31:01 +00003989
3990 obj = FPDFPage_GetObject(page, 33);
3991 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00003992 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
3993 EXPECT_FLOAT_EQ(53.0f, matrix.a);
3994 EXPECT_FLOAT_EQ(0.0f, matrix.b);
3995 EXPECT_FLOAT_EQ(0.0f, matrix.c);
3996 EXPECT_FLOAT_EQ(43.0f, matrix.d);
3997 EXPECT_FLOAT_EQ(72.0f, matrix.e);
3998 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00003999
4000 obj = FPDFPage_GetObject(page, 34);
4001 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00004002 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4003 EXPECT_FLOAT_EQ(70.0f, matrix.a);
4004 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4005 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4006 EXPECT_FLOAT_EQ(51.0f, matrix.d);
4007 EXPECT_FLOAT_EQ(216.0f, matrix.e);
4008 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00004009
4010 obj = FPDFPage_GetObject(page, 35);
4011 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00004012 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4013 EXPECT_FLOAT_EQ(69.0f, matrix.a);
4014 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4015 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4016 EXPECT_FLOAT_EQ(51.0f, matrix.d);
4017 EXPECT_FLOAT_EQ(360.0f, matrix.e);
4018 EXPECT_FLOAT_EQ(646.510009765625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00004019
4020 obj = FPDFPage_GetObject(page, 36);
4021 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00004022 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4023 EXPECT_FLOAT_EQ(59.0f, matrix.a);
4024 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4025 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4026 EXPECT_FLOAT_EQ(45.0f, matrix.d);
4027 EXPECT_FLOAT_EQ(72.0f, matrix.e);
4028 EXPECT_FLOAT_EQ(553.510009765625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00004029
4030 obj = FPDFPage_GetObject(page, 37);
4031 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00004032 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4033 EXPECT_FLOAT_EQ(55.94000244140625f, matrix.a);
4034 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4035 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4036 EXPECT_FLOAT_EQ(46.950000762939453f, matrix.d);
4037 EXPECT_FLOAT_EQ(216.0f, matrix.e);
4038 EXPECT_FLOAT_EQ(552.510009765625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00004039
4040 obj = FPDFPage_GetObject(page, 38);
4041 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
Lei Zhangc8601bf2021-06-29 23:19:27 +00004042 EXPECT_TRUE(FPDFPageObj_GetMatrix(obj, &matrix));
4043 EXPECT_FLOAT_EQ(70.528999328613281f, matrix.a);
4044 EXPECT_FLOAT_EQ(0.0f, matrix.b);
4045 EXPECT_FLOAT_EQ(0.0f, matrix.c);
4046 EXPECT_FLOAT_EQ(43.149997711181641f, matrix.d);
4047 EXPECT_FLOAT_EQ(360.0f, matrix.e);
4048 EXPECT_FLOAT_EQ(553.3599853515625f, matrix.f);
Lei Zhang866d6882018-10-24 17:31:01 +00004049
4050 UnloadPage(page);
4051}
4052
Lei Zhangab41f252018-12-23 03:10:50 +00004053TEST_F(FPDFEditEmbedderTest, DestroyPageObject) {
Jane Liu2e5f0ae2017-08-08 15:23:27 -04004054 FPDF_PAGEOBJECT rect = FPDFPageObj_CreateNewRect(10, 10, 20, 20);
4055 ASSERT_TRUE(rect);
4056
4057 // There should be no memory leaks with a call to FPDFPageObj_Destroy().
4058 FPDFPageObj_Destroy(rect);
4059}
Jane Liube63ab92017-08-09 14:09:34 -04004060
Lei Zhangab41f252018-12-23 03:10:50 +00004061TEST_F(FPDFEditEmbedderTest, GetImageFilters) {
Daniel Hosseinian5af51b62020-07-18 00:53:43 +00004062 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
Jane Liube63ab92017-08-09 14:09:34 -04004063 FPDF_PAGE page = LoadPage(0);
4064 ASSERT_TRUE(page);
4065
4066 // Verify that retrieving the filter of a non-image object would fail.
4067 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 32);
4068 ASSERT_NE(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4069 ASSERT_EQ(0, FPDFImageObj_GetImageFilterCount(obj));
4070 EXPECT_EQ(0u, FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0));
4071
4072 // Verify the returned filter string for an image object with a single filter.
4073 obj = FPDFPage_GetObject(page, 33);
4074 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4075 ASSERT_EQ(1, FPDFImageObj_GetImageFilterCount(obj));
4076 unsigned long len = FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0);
4077 std::vector<char> buf(len);
Lei Zhang0733a1b2017-08-31 12:36:31 -07004078 static constexpr char kFlateDecode[] = "FlateDecode";
4079 EXPECT_EQ(sizeof(kFlateDecode),
4080 FPDFImageObj_GetImageFilter(obj, 0, buf.data(), len));
4081 EXPECT_STREQ(kFlateDecode, buf.data());
Jane Liube63ab92017-08-09 14:09:34 -04004082 EXPECT_EQ(0u, FPDFImageObj_GetImageFilter(obj, 1, nullptr, 0));
4083
4084 // Verify all the filters for an image object with a list of filters.
4085 obj = FPDFPage_GetObject(page, 38);
4086 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4087 ASSERT_EQ(2, FPDFImageObj_GetImageFilterCount(obj));
4088 len = FPDFImageObj_GetImageFilter(obj, 0, nullptr, 0);
4089 buf.clear();
4090 buf.resize(len);
Lei Zhang0733a1b2017-08-31 12:36:31 -07004091 static constexpr char kASCIIHexDecode[] = "ASCIIHexDecode";
4092 EXPECT_EQ(sizeof(kASCIIHexDecode),
4093 FPDFImageObj_GetImageFilter(obj, 0, buf.data(), len));
4094 EXPECT_STREQ(kASCIIHexDecode, buf.data());
Jane Liube63ab92017-08-09 14:09:34 -04004095
4096 len = FPDFImageObj_GetImageFilter(obj, 1, nullptr, 0);
4097 buf.clear();
4098 buf.resize(len);
Lei Zhang0733a1b2017-08-31 12:36:31 -07004099 static constexpr char kDCTDecode[] = "DCTDecode";
4100 EXPECT_EQ(sizeof(kDCTDecode),
4101 FPDFImageObj_GetImageFilter(obj, 1, buf.data(), len));
4102 EXPECT_STREQ(kDCTDecode, buf.data());
Jane Liube63ab92017-08-09 14:09:34 -04004103
4104 UnloadPage(page);
4105}
Jane Liuca898292017-08-16 11:25:35 -04004106
Lei Zhangab41f252018-12-23 03:10:50 +00004107TEST_F(FPDFEditEmbedderTest, GetImageMetadata) {
Jane Liuca898292017-08-16 11:25:35 -04004108 ASSERT_TRUE(OpenDocument("embedded_images.pdf"));
4109 FPDF_PAGE page = LoadPage(0);
4110 ASSERT_TRUE(page);
4111
4112 // Check that getting the metadata of a null object would fail.
4113 FPDF_IMAGEOBJ_METADATA metadata;
4114 EXPECT_FALSE(FPDFImageObj_GetImageMetadata(nullptr, page, &metadata));
4115
4116 // Check that receiving the metadata with a null metadata object would fail.
4117 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 35);
4118 EXPECT_FALSE(FPDFImageObj_GetImageMetadata(obj, page, nullptr));
4119
4120 // Check that when retrieving an image object's metadata without passing in
4121 // |page|, all values are correct, with the last two being default values.
4122 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4123 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, nullptr, &metadata));
Julian Lungerecd063e2017-12-27 10:18:50 -05004124 EXPECT_EQ(7, metadata.marked_content_id);
Jane Liuca898292017-08-16 11:25:35 -04004125 EXPECT_EQ(92u, metadata.width);
4126 EXPECT_EQ(68u, metadata.height);
Lei Zhang351e8b02018-12-20 01:10:06 +00004127 EXPECT_FLOAT_EQ(96.0f, metadata.horizontal_dpi);
4128 EXPECT_FLOAT_EQ(96.0f, metadata.vertical_dpi);
Jane Liuca898292017-08-16 11:25:35 -04004129 EXPECT_EQ(0u, metadata.bits_per_pixel);
4130 EXPECT_EQ(FPDF_COLORSPACE_UNKNOWN, metadata.colorspace);
4131
4132 // Verify the metadata of a bitmap image with indexed colorspace.
4133 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
Julian Lungerecd063e2017-12-27 10:18:50 -05004134 EXPECT_EQ(7, metadata.marked_content_id);
Jane Liuca898292017-08-16 11:25:35 -04004135 EXPECT_EQ(92u, metadata.width);
4136 EXPECT_EQ(68u, metadata.height);
Lei Zhang351e8b02018-12-20 01:10:06 +00004137 EXPECT_FLOAT_EQ(96.0f, metadata.horizontal_dpi);
4138 EXPECT_FLOAT_EQ(96.0f, metadata.vertical_dpi);
Jane Liuca898292017-08-16 11:25:35 -04004139 EXPECT_EQ(1u, metadata.bits_per_pixel);
4140 EXPECT_EQ(FPDF_COLORSPACE_INDEXED, metadata.colorspace);
4141
4142 // Verify the metadata of an image with RGB colorspace.
4143 obj = FPDFPage_GetObject(page, 37);
4144 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4145 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
Julian Lungerecd063e2017-12-27 10:18:50 -05004146 EXPECT_EQ(9, metadata.marked_content_id);
Jane Liuca898292017-08-16 11:25:35 -04004147 EXPECT_EQ(126u, metadata.width);
4148 EXPECT_EQ(106u, metadata.height);
Lei Zhang351e8b02018-12-20 01:10:06 +00004149 EXPECT_FLOAT_EQ(162.173752f, metadata.horizontal_dpi);
4150 EXPECT_FLOAT_EQ(162.555878f, metadata.vertical_dpi);
Jane Liuca898292017-08-16 11:25:35 -04004151 EXPECT_EQ(24u, metadata.bits_per_pixel);
4152 EXPECT_EQ(FPDF_COLORSPACE_DEVICERGB, metadata.colorspace);
4153
4154 UnloadPage(page);
4155}
Lei Zhangdc1b7392020-05-14 21:15:53 +00004156
4157TEST_F(FPDFEditEmbedderTest, GetImageMetadataJpxLzw) {
4158 ASSERT_TRUE(OpenDocument("jpx_lzw.pdf"));
4159 FPDF_PAGE page = LoadPage(0);
4160 ASSERT_TRUE(page);
4161
4162 FPDF_PAGEOBJECT obj = FPDFPage_GetObject(page, 0);
4163 ASSERT_EQ(FPDF_PAGEOBJ_IMAGE, FPDFPageObj_GetType(obj));
4164
4165 FPDF_IMAGEOBJ_METADATA metadata;
4166 ASSERT_TRUE(FPDFImageObj_GetImageMetadata(obj, page, &metadata));
4167 EXPECT_EQ(-1, metadata.marked_content_id);
4168 EXPECT_EQ(612u, metadata.width);
4169 EXPECT_EQ(792u, metadata.height);
4170 EXPECT_FLOAT_EQ(72.0f, metadata.horizontal_dpi);
4171 EXPECT_FLOAT_EQ(72.0f, metadata.vertical_dpi);
4172 EXPECT_EQ(24u, metadata.bits_per_pixel);
4173 EXPECT_EQ(FPDF_COLORSPACE_UNKNOWN, metadata.colorspace);
4174
4175 UnloadPage(page);
4176}