1 // Copyright 2018 The PDFium Authors
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 <iterator>
8 #include <memory>
9 #include <utility>
10
11 #include "core/fpdfapi/page/cpdf_transferfunc.h"
12 #include "core/fpdfapi/parser/cpdf_array.h"
13 #include "core/fpdfapi/parser/cpdf_dictionary.h"
14 #include "core/fpdfapi/parser/cpdf_number.h"
15 #include "core/fpdfapi/parser/cpdf_stream.h"
16 #include "core/fxcrt/data_vector.h"
17 #include "testing/gtest/include/gtest/gtest.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 func_dict->SetNewFor<CPDF_Number>("BitsPerSample", 8);
77
78 auto domain_array = func_dict->SetNewFor<CPDF_Array>("Domain");
79 domain_array->AppendNew<CPDF_Number>(0);
80 domain_array->AppendNew<CPDF_Number>(1);
81
82 auto range_array = func_dict->SetNewFor<CPDF_Array>("Range");
83 range_array->AppendNew<CPDF_Number>(0);
84 range_array->AppendNew<CPDF_Number>(0.5f);
85
86 auto size_array = func_dict->SetNewFor<CPDF_Array>("Size");
87 size_array->AppendNew<CPDF_Number>(4);
88
89 static constexpr uint8_t kContents[] = "1234";
90 return pdfium::MakeRetain<CPDF_Stream>(
91 DataVector<uint8_t>(std::begin(kContents), std::end(kContents)),
92 std::move(func_dict));
93 }
94
CreateType2FunctionDict()95 RetainPtr<CPDF_Dictionary> CreateType2FunctionDict() {
96 auto func_dict = pdfium::MakeRetain<CPDF_Dictionary>();
97 func_dict->SetNewFor<CPDF_Number>("FunctionType", 2);
98 func_dict->SetNewFor<CPDF_Number>("N", 1);
99
100 auto domain_array = func_dict->SetNewFor<CPDF_Array>("Domain");
101 domain_array->AppendNew<CPDF_Number>(0);
102 domain_array->AppendNew<CPDF_Number>(1);
103
104 auto c0_array = func_dict->SetNewFor<CPDF_Array>("C0");
105 c0_array->AppendNew<CPDF_Number>(0.1f);
106 c0_array->AppendNew<CPDF_Number>(0.2f);
107 c0_array->AppendNew<CPDF_Number>(0.8f);
108
109 auto c1_array = func_dict->SetNewFor<CPDF_Array>("C1");
110 c1_array->AppendNew<CPDF_Number>(0.05f);
111 c1_array->AppendNew<CPDF_Number>(0.01f);
112 c1_array->AppendNew<CPDF_Number>(0.4f);
113
114 return func_dict;
115 }
116
CreateType4FunctionStream()117 RetainPtr<CPDF_Stream> CreateType4FunctionStream() {
118 auto func_dict = pdfium::MakeRetain<CPDF_Dictionary>();
119 func_dict->SetNewFor<CPDF_Number>("FunctionType", 4);
120
121 auto domain_array = func_dict->SetNewFor<CPDF_Array>("Domain");
122 domain_array->AppendNew<CPDF_Number>(0);
123 domain_array->AppendNew<CPDF_Number>(1);
124
125 auto range_array = func_dict->SetNewFor<CPDF_Array>("Range");
126 range_array->AppendNew<CPDF_Number>(-1);
127 range_array->AppendNew<CPDF_Number>(1);
128
129 static constexpr uint8_t kContents[] = "{ 360 mul sin 2 div }";
130 return pdfium::MakeRetain<CPDF_Stream>(
131 DataVector<uint8_t>(std::begin(kContents), std::end(kContents)),
132 std::move(func_dict));
133 }
134
CreateBadType4FunctionStream()135 RetainPtr<CPDF_Stream> CreateBadType4FunctionStream() {
136 auto func_dict = pdfium::MakeRetain<CPDF_Dictionary>();
137 func_dict->SetNewFor<CPDF_Number>("FunctionType", 4);
138
139 auto domain_array = func_dict->SetNewFor<CPDF_Array>("Domain");
140 domain_array->AppendNew<CPDF_Number>(0);
141 domain_array->AppendNew<CPDF_Number>(1);
142
143 auto range_array = func_dict->SetNewFor<CPDF_Array>("Range");
144 range_array->AppendNew<CPDF_Number>(-1);
145 range_array->AppendNew<CPDF_Number>(1);
146
147 static constexpr uint8_t kContents[] = "garbage";
148 return pdfium::MakeRetain<CPDF_Stream>(
149 DataVector<uint8_t>(std::begin(kContents), std::end(kContents)),
150 std::move(func_dict));
151 }
152
153 class TestDocRenderData : public CPDF_DocRenderData {
154 public:
155 TestDocRenderData() = default;
156
CreateTransferFuncForTesting(RetainPtr<const CPDF_Object> pObj) const157 RetainPtr<CPDF_TransferFunc> CreateTransferFuncForTesting(
158 RetainPtr<const CPDF_Object> pObj) const {
159 return CreateTransferFunc(std::move(pObj));
160 }
161 };
162
TEST(CPDF_DocRenderDataTest,TransferFunctionOne)163 TEST(CPDF_DocRenderDataTest, TransferFunctionOne) {
164 RetainPtr<CPDF_Dictionary> func_dict = CreateType2FunctionDict();
165
166 TestDocRenderData render_data;
167 auto func = render_data.CreateTransferFuncForTesting(func_dict);
168 ASSERT_TRUE(func);
169 EXPECT_FALSE(func->GetIdentity());
170
171 auto r_samples = func->GetSamplesR();
172 auto g_samples = func->GetSamplesG();
173 auto b_samples = func->GetSamplesB();
174 ASSERT_EQ(std::size(kExpectedType2FunctionSamples), r_samples.size());
175 ASSERT_EQ(std::size(kExpectedType2FunctionSamples), g_samples.size());
176 ASSERT_EQ(std::size(kExpectedType2FunctionSamples), b_samples.size());
177
178 for (size_t i = 0; i < std::size(kExpectedType2FunctionSamples); ++i) {
179 EXPECT_EQ(kExpectedType2FunctionSamples[i], r_samples[i]);
180 EXPECT_EQ(kExpectedType2FunctionSamples[i], g_samples[i]);
181 EXPECT_EQ(kExpectedType2FunctionSamples[i], b_samples[i]);
182 }
183
184 EXPECT_EQ(0x000d0d0du, func->TranslateColor(0x00ffffff));
185 EXPECT_EQ(0x000d1a1au, func->TranslateColor(0x00ff0000));
186 EXPECT_EQ(0x001a0d1au, func->TranslateColor(0x0000ff00));
187 EXPECT_EQ(0x001a1a0du, func->TranslateColor(0x000000ff));
188 EXPECT_EQ(0x000f0f0fu, func->TranslateColor(0x00cccccc));
189 EXPECT_EQ(0x00191715u, func->TranslateColor(0x00123456));
190 EXPECT_EQ(0x000d0d0du, func->TranslateColor(0xffffffff));
191 EXPECT_EQ(0x001a1a1au, func->TranslateColor(0xff000000));
192 EXPECT_EQ(0x000d0d0du, func->TranslateColor(0xccffffff));
193 EXPECT_EQ(0x001a1a1au, func->TranslateColor(0x99000000));
194 }
195
TEST(CPDF_DocRenderDataTest,TransferFunctionArray)196 TEST(CPDF_DocRenderDataTest, TransferFunctionArray) {
197 auto func_array = pdfium::MakeRetain<CPDF_Array>();
198 func_array->Append(CreateType0FunctionStream());
199 func_array->Append(CreateType2FunctionDict());
200 func_array->Append(CreateType4FunctionStream());
201
202 TestDocRenderData render_data;
203 auto func = render_data.CreateTransferFuncForTesting(func_array);
204 ASSERT_TRUE(func);
205 EXPECT_FALSE(func->GetIdentity());
206
207 auto r_samples = func->GetSamplesR();
208 auto g_samples = func->GetSamplesG();
209 auto b_samples = func->GetSamplesB();
210 ASSERT_EQ(std::size(kExpectedType0FunctionSamples), r_samples.size());
211 ASSERT_EQ(std::size(kExpectedType2FunctionSamples), g_samples.size());
212 ASSERT_EQ(std::size(kExpectedType4FunctionSamples), b_samples.size());
213
214 for (size_t i = 0; i < std::size(kExpectedType2FunctionSamples); ++i) {
215 EXPECT_EQ(kExpectedType0FunctionSamples[i], r_samples[i]);
216 EXPECT_EQ(kExpectedType2FunctionSamples[i], g_samples[i]);
217 EXPECT_EQ(kExpectedType4FunctionSamples[i], b_samples[i]);
218 }
219
220 EXPECT_EQ(0x001a0d00u, func->TranslateColor(0x00ffffff));
221 EXPECT_EQ(0x001a1a00u, func->TranslateColor(0x00ff0000));
222 EXPECT_EQ(0x00190d00u, func->TranslateColor(0x0000ff00));
223 EXPECT_EQ(0x00191a00u, func->TranslateColor(0x000000ff));
224 EXPECT_EQ(0x001a0f87u, func->TranslateColor(0x00cccccc));
225 EXPECT_EQ(0x0019176du, func->TranslateColor(0x00123456));
226 EXPECT_EQ(0x001a0d00u, func->TranslateColor(0xffffffff));
227 EXPECT_EQ(0x00191a00u, func->TranslateColor(0xff000000));
228 EXPECT_EQ(0x001a0d00u, func->TranslateColor(0xccffffff));
229 EXPECT_EQ(0x00191a00u, func->TranslateColor(0x99000000));
230 }
231
TEST(CPDF_DocRenderDataTest,BadTransferFunctions)232 TEST(CPDF_DocRenderDataTest, BadTransferFunctions) {
233 {
234 auto func_stream = CreateBadType4FunctionStream();
235
236 TestDocRenderData render_data;
237 auto func = render_data.CreateTransferFuncForTesting(func_stream);
238 EXPECT_FALSE(func);
239 }
240
241 {
242 auto func_array = pdfium::MakeRetain<CPDF_Array>();
243
244 TestDocRenderData render_data;
245 auto func = render_data.CreateTransferFuncForTesting(func_array);
246 EXPECT_FALSE(func);
247 }
248
249 {
250 auto func_array = pdfium::MakeRetain<CPDF_Array>();
251 func_array->Append(CreateType0FunctionStream());
252 func_array->Append(CreateType2FunctionDict());
253 func_array->Append(CreateBadType4FunctionStream());
254
255 TestDocRenderData render_data;
256 auto func = render_data.CreateTransferFuncForTesting(func_array);
257 EXPECT_FALSE(func);
258 }
259 }
260
261 } // namespace
262