1 // Copyright 2018 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
5 #include "core/fpdfapi/render/cpdf_docrenderdata.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "core/fpdfapi/page/cpdf_transferfunc.h"
11 #include "core/fpdfapi/parser/cpdf_array.h"
12 #include "core/fpdfapi/parser/cpdf_dictionary.h"
13 #include "core/fpdfapi/parser/cpdf_number.h"
14 #include "core/fpdfapi/parser/cpdf_stream.h"
15 #include "core/fxcrt/fx_memory_wrappers.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "third_party/base/ptr_util.h"
18
19 namespace {
20
21 constexpr uint8_t kExpectedType0FunctionSamples[] = {
22 0, 3, 6, 9, 13, 16, 19, 22, 25, 28, 31, 34, 37, 40, 43,
23 46, 49, 52, 55, 58, 60, 63, 66, 68, 71, 74, 76, 79, 81, 84,
24 86, 88, 90, 93, 95, 97, 99, 101, 103, 105, 106, 108, 110, 111, 113,
25 114, 115, 117, 118, 119, 120, 121, 122, 123, 124, 125, 125, 126, 126, 127,
26 127, 127, 127, 127, 127, 127, 127, 127, 127, 126, 126, 125, 125, 124, 123,
27 123, 122, 121, 120, 119, 117, 116, 115, 113, 112, 110, 109, 107, 105, 104,
28 102, 100, 98, 96, 94, 92, 89, 87, 85, 82, 80, 77, 75, 72, 70,
29 67, 64, 62, 59, 56, 53, 50, 48, 45, 42, 39, 36, 33, 30, 27,
30 23, 20, 17, 14, 11, 8, 5, 2, 254, 251, 248, 245, 242, 239, 236,
31 233, 229, 226, 223, 220, 217, 214, 211, 208, 206, 203, 200, 197, 194, 192,
32 189, 186, 184, 181, 179, 176, 174, 171, 169, 167, 164, 162, 160, 158, 156,
33 154, 152, 151, 149, 147, 146, 144, 143, 141, 140, 139, 137, 136, 135, 134,
34 133, 133, 132, 131, 131, 130, 130, 129, 129, 129, 129, 129, 129, 129, 129,
35 129, 129, 130, 130, 131, 131, 132, 133, 134, 135, 136, 137, 138, 139, 141,
36 142, 143, 145, 146, 148, 150, 151, 153, 155, 157, 159, 161, 163, 166, 168,
37 170, 172, 175, 177, 180, 182, 185, 188, 190, 193, 196, 198, 201, 204, 207,
38 210, 213, 216, 219, 222, 225, 228, 231, 234, 237, 240, 243, 247, 250, 253,
39 0};
40
41 constexpr uint8_t kExpectedType2FunctionSamples[] = {
42 26, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
43 25, 25, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
44 24, 24, 24, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
45 23, 23, 23, 23, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
46 22, 22, 22, 22, 22, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
47 21, 21, 21, 21, 21, 21, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
48 20, 20, 20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
49 19, 19, 19, 19, 19, 19, 19, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
50 18, 18, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
51 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
52 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15,
53 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14,
54 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13,
55 13, 13, 13, 13, 13, 13, 13, 13, 13};
56
57 constexpr uint8_t kExpectedType4FunctionSamples[] = {
58 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
59 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
60 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
61 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
62 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
63 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
64 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
65 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
66 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26,
67 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
68 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
69 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
70 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
71 26, 26, 26, 26, 26, 26, 26, 26, 26};
72
CreateType0FunctionStream()73 RetainPtr<CPDF_Stream> CreateType0FunctionStream() {
74 auto func_dict = pdfium::MakeRetain<CPDF_Dictionary>();
75 func_dict->SetNewFor<CPDF_Number>("FunctionType", 0);
76
77 CPDF_Array* domain_array = func_dict->SetNewFor<CPDF_Array>("Domain");
78 domain_array->AddNew<CPDF_Number>(0);
79 domain_array->AddNew<CPDF_Number>(1);
80
81 CPDF_Array* range_array = func_dict->SetNewFor<CPDF_Array>("Range");
82 range_array->AddNew<CPDF_Number>(0);
83 range_array->AddNew<CPDF_Number>(0.5f);
84
85 CPDF_Array* size_array = func_dict->SetNewFor<CPDF_Array>("Size");
86 size_array->AddNew<CPDF_Number>(4);
87
88 func_dict->SetNewFor<CPDF_Number>("BitsPerSample", 8);
89
90 static const char content[] = "1234";
91 size_t len = FX_ArraySize(content);
92 std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, len));
93 memcpy(buf.get(), content, len);
94 return pdfium::MakeRetain<CPDF_Stream>(std::move(buf), len,
95 std::move(func_dict));
96 }
97
CreateType2FunctionDict()98 RetainPtr<CPDF_Dictionary> CreateType2FunctionDict() {
99 auto func_dict = pdfium::MakeRetain<CPDF_Dictionary>();
100 func_dict->SetNewFor<CPDF_Number>("FunctionType", 2);
101 func_dict->SetNewFor<CPDF_Number>("N", 1);
102
103 CPDF_Array* domain_array = func_dict->SetNewFor<CPDF_Array>("Domain");
104 domain_array->AddNew<CPDF_Number>(0);
105 domain_array->AddNew<CPDF_Number>(1);
106
107 CPDF_Array* c0_array = func_dict->SetNewFor<CPDF_Array>("C0");
108 c0_array->AddNew<CPDF_Number>(0.1f);
109 c0_array->AddNew<CPDF_Number>(0.2f);
110 c0_array->AddNew<CPDF_Number>(0.8f);
111
112 CPDF_Array* c1_array = func_dict->SetNewFor<CPDF_Array>("C1");
113 c1_array->AddNew<CPDF_Number>(0.05f);
114 c1_array->AddNew<CPDF_Number>(0.01f);
115 c1_array->AddNew<CPDF_Number>(0.4f);
116
117 return func_dict;
118 }
119
CreateType4FunctionStream()120 RetainPtr<CPDF_Stream> CreateType4FunctionStream() {
121 auto func_dict = pdfium::MakeRetain<CPDF_Dictionary>();
122 func_dict->SetNewFor<CPDF_Number>("FunctionType", 4);
123
124 CPDF_Array* domain_array = func_dict->SetNewFor<CPDF_Array>("Domain");
125 domain_array->AddNew<CPDF_Number>(0);
126 domain_array->AddNew<CPDF_Number>(1);
127
128 CPDF_Array* range_array = func_dict->SetNewFor<CPDF_Array>("Range");
129 range_array->AddNew<CPDF_Number>(-1);
130 range_array->AddNew<CPDF_Number>(1);
131
132 static const char content[] = "{ 360 mul sin 2 div }";
133 size_t len = FX_ArraySize(content);
134 std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, len));
135 memcpy(buf.get(), content, len);
136 return pdfium::MakeRetain<CPDF_Stream>(std::move(buf), len,
137 std::move(func_dict));
138 }
139
CreateBadType4FunctionStream()140 RetainPtr<CPDF_Stream> CreateBadType4FunctionStream() {
141 auto func_dict = pdfium::MakeRetain<CPDF_Dictionary>();
142 func_dict->SetNewFor<CPDF_Number>("FunctionType", 4);
143
144 CPDF_Array* domain_array = func_dict->SetNewFor<CPDF_Array>("Domain");
145 domain_array->AddNew<CPDF_Number>(0);
146 domain_array->AddNew<CPDF_Number>(1);
147
148 CPDF_Array* range_array = func_dict->SetNewFor<CPDF_Array>("Range");
149 range_array->AddNew<CPDF_Number>(-1);
150 range_array->AddNew<CPDF_Number>(1);
151
152 static const char content[] = "garbage";
153 size_t len = FX_ArraySize(content);
154 std::unique_ptr<uint8_t, FxFreeDeleter> buf(FX_Alloc(uint8_t, len));
155 memcpy(buf.get(), content, len);
156 return pdfium::MakeRetain<CPDF_Stream>(std::move(buf), len,
157 std::move(func_dict));
158 }
159
160 class TestDocRenderData : public CPDF_DocRenderData {
161 public:
TestDocRenderData()162 TestDocRenderData() : CPDF_DocRenderData() {}
163
CreateTransferFuncForTesting(const CPDF_Object * pObj) const164 RetainPtr<CPDF_TransferFunc> CreateTransferFuncForTesting(
165 const CPDF_Object* pObj) const {
166 return CreateTransferFunc(pObj);
167 }
168 };
169
TEST(CPDF_DocRenderDataTest,TransferFunctionOne)170 TEST(CPDF_DocRenderDataTest, TransferFunctionOne) {
171 RetainPtr<CPDF_Dictionary> func_dict = CreateType2FunctionDict();
172
173 TestDocRenderData render_data;
174 auto func = render_data.CreateTransferFuncForTesting(func_dict.Get());
175 ASSERT_TRUE(func);
176 EXPECT_FALSE(func->GetIdentity());
177
178 auto r_samples = func->GetSamplesR();
179 auto g_samples = func->GetSamplesG();
180 auto b_samples = func->GetSamplesB();
181 ASSERT_EQ(FX_ArraySize(kExpectedType2FunctionSamples), r_samples.size());
182 ASSERT_EQ(FX_ArraySize(kExpectedType2FunctionSamples), g_samples.size());
183 ASSERT_EQ(FX_ArraySize(kExpectedType2FunctionSamples), b_samples.size());
184
185 for (size_t i = 0; i < FX_ArraySize(kExpectedType2FunctionSamples); ++i) {
186 EXPECT_EQ(kExpectedType2FunctionSamples[i], r_samples[i]);
187 EXPECT_EQ(kExpectedType2FunctionSamples[i], g_samples[i]);
188 EXPECT_EQ(kExpectedType2FunctionSamples[i], b_samples[i]);
189 }
190
191 EXPECT_EQ(0x000d0d0du, func->TranslateColor(0x00ffffff));
192 EXPECT_EQ(0x000d1a1au, func->TranslateColor(0x00ff0000));
193 EXPECT_EQ(0x001a0d1au, func->TranslateColor(0x0000ff00));
194 EXPECT_EQ(0x001a1a0du, func->TranslateColor(0x000000ff));
195 EXPECT_EQ(0x000f0f0fu, func->TranslateColor(0x00cccccc));
196 EXPECT_EQ(0x00191715u, func->TranslateColor(0x00123456));
197 EXPECT_EQ(0x000d0d0du, func->TranslateColor(0xffffffff));
198 EXPECT_EQ(0x001a1a1au, func->TranslateColor(0xff000000));
199 EXPECT_EQ(0x000d0d0du, func->TranslateColor(0xccffffff));
200 EXPECT_EQ(0x001a1a1au, func->TranslateColor(0x99000000));
201 }
202
TEST(CPDF_DocRenderDataTest,TransferFunctionArray)203 TEST(CPDF_DocRenderDataTest, TransferFunctionArray) {
204 auto func_array = pdfium::MakeRetain<CPDF_Array>();
205 func_array->Add(CreateType0FunctionStream());
206 func_array->Add(CreateType2FunctionDict());
207 func_array->Add(CreateType4FunctionStream());
208
209 TestDocRenderData render_data;
210 auto func = render_data.CreateTransferFuncForTesting(func_array.Get());
211 ASSERT_TRUE(func);
212 EXPECT_FALSE(func->GetIdentity());
213
214 auto r_samples = func->GetSamplesR();
215 auto g_samples = func->GetSamplesG();
216 auto b_samples = func->GetSamplesB();
217 ASSERT_EQ(FX_ArraySize(kExpectedType0FunctionSamples), r_samples.size());
218 ASSERT_EQ(FX_ArraySize(kExpectedType2FunctionSamples), g_samples.size());
219 ASSERT_EQ(FX_ArraySize(kExpectedType4FunctionSamples), b_samples.size());
220
221 for (size_t i = 0; i < FX_ArraySize(kExpectedType2FunctionSamples); ++i) {
222 EXPECT_EQ(kExpectedType0FunctionSamples[i], r_samples[i]);
223 EXPECT_EQ(kExpectedType2FunctionSamples[i], g_samples[i]);
224 EXPECT_EQ(kExpectedType4FunctionSamples[i], b_samples[i]);
225 }
226
227 EXPECT_EQ(0x001a0d00u, func->TranslateColor(0x00ffffff));
228 EXPECT_EQ(0x001a1a00u, func->TranslateColor(0x00ff0000));
229 EXPECT_EQ(0x00190d00u, func->TranslateColor(0x0000ff00));
230 EXPECT_EQ(0x00191a00u, func->TranslateColor(0x000000ff));
231 EXPECT_EQ(0x001a0f87u, func->TranslateColor(0x00cccccc));
232 EXPECT_EQ(0x0019176du, func->TranslateColor(0x00123456));
233 EXPECT_EQ(0x001a0d00u, func->TranslateColor(0xffffffff));
234 EXPECT_EQ(0x00191a00u, func->TranslateColor(0xff000000));
235 EXPECT_EQ(0x001a0d00u, func->TranslateColor(0xccffffff));
236 EXPECT_EQ(0x00191a00u, func->TranslateColor(0x99000000));
237 }
238
TEST(CPDF_DocRenderDataTest,BadTransferFunctions)239 TEST(CPDF_DocRenderDataTest, BadTransferFunctions) {
240 {
241 auto func_stream = CreateBadType4FunctionStream();
242
243 TestDocRenderData render_data;
244 auto func = render_data.CreateTransferFuncForTesting(func_stream.Get());
245 EXPECT_FALSE(func);
246 }
247
248 {
249 auto func_array = pdfium::MakeRetain<CPDF_Array>();
250
251 TestDocRenderData render_data;
252 auto func = render_data.CreateTransferFuncForTesting(func_array.Get());
253 EXPECT_FALSE(func);
254 }
255
256 {
257 auto func_array = pdfium::MakeRetain<CPDF_Array>();
258 func_array->Add(CreateType0FunctionStream());
259 func_array->Add(CreateType2FunctionDict());
260 func_array->Add(CreateBadType4FunctionStream());
261
262 TestDocRenderData render_data;
263 auto func = render_data.CreateTransferFuncForTesting(func_array.Get());
264 EXPECT_FALSE(func);
265 }
266 }
267
268 } // namespace
269