1 // Copyright 2017 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/page/cpdf_psengine.h"
6
7 #include <iterator>
8 #include <limits>
9
10 #include "core/fxcrt/notreached.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12
13 namespace {
14
DoOperator0(CPDF_PSEngine * engine,PDF_PSOP op)15 float DoOperator0(CPDF_PSEngine* engine, PDF_PSOP op) {
16 EXPECT_EQ(0u, engine->GetStackSize());
17 engine->DoOperator(op);
18 float ret = engine->Pop();
19 EXPECT_EQ(0u, engine->GetStackSize());
20 return ret;
21 }
22
DoOperator1(CPDF_PSEngine * engine,float v1,PDF_PSOP op)23 float DoOperator1(CPDF_PSEngine* engine, float v1, PDF_PSOP op) {
24 EXPECT_EQ(0u, engine->GetStackSize());
25 engine->Push(v1);
26 engine->DoOperator(op);
27 float ret = engine->Pop();
28 EXPECT_EQ(0u, engine->GetStackSize());
29 return ret;
30 }
31
DoOperator2(CPDF_PSEngine * engine,float v1,float v2,PDF_PSOP op)32 float DoOperator2(CPDF_PSEngine* engine, float v1, float v2, PDF_PSOP op) {
33 EXPECT_EQ(0u, engine->GetStackSize());
34 engine->Push(v1);
35 engine->Push(v2);
36 engine->DoOperator(op);
37 float ret = engine->Pop();
38 EXPECT_EQ(0u, engine->GetStackSize());
39 return ret;
40 }
41
42 } // namespace
43
TEST(CPDFPSProcTest,AddOperator)44 TEST(CPDFPSProcTest, AddOperator) {
45 static const struct {
46 const char* name;
47 PDF_PSOP op;
48 } kTestData[] = {
49 {"add", PSOP_ADD}, {"sub", PSOP_SUB},
50 {"mul", PSOP_MUL}, {"div", PSOP_DIV},
51 {"idiv", PSOP_IDIV}, {"mod", PSOP_MOD},
52 {"neg", PSOP_NEG}, {"abs", PSOP_ABS},
53 {"ceiling", PSOP_CEILING}, {"floor", PSOP_FLOOR},
54 {"round", PSOP_ROUND}, {"truncate", PSOP_TRUNCATE},
55 {"sqrt", PSOP_SQRT}, {"sin", PSOP_SIN},
56 {"cos", PSOP_COS}, {"atan", PSOP_ATAN},
57 {"exp", PSOP_EXP}, {"ln", PSOP_LN},
58 {"log", PSOP_LOG}, {"cvi", PSOP_CVI},
59 {"cvr", PSOP_CVR}, {"eq", PSOP_EQ},
60 {"ne", PSOP_NE}, {"gt", PSOP_GT},
61 {"ge", PSOP_GE}, {"lt", PSOP_LT},
62 {"le", PSOP_LE}, {"and", PSOP_AND},
63 {"or", PSOP_OR}, {"xor", PSOP_XOR},
64 {"not", PSOP_NOT}, {"bitshift", PSOP_BITSHIFT},
65 {"true", PSOP_TRUE}, {"false", PSOP_FALSE},
66 {"if", PSOP_IF}, {"ifelse", PSOP_IFELSE},
67 {"pop", PSOP_POP}, {"exch", PSOP_EXCH},
68 {"dup", PSOP_DUP}, {"copy", PSOP_COPY},
69 {"index", PSOP_INDEX}, {"roll", PSOP_ROLL},
70 {"55", PSOP_CONST}, {"123.4", PSOP_CONST},
71 {"-5", PSOP_CONST}, {"invalid", PSOP_CONST},
72 };
73
74 CPDF_PSProc proc;
75 for (const auto& item : kTestData) {
76 ByteStringView word(item.name);
77 proc.AddOperatorForTesting(word);
78 const std::unique_ptr<CPDF_PSOP>& new_psop = proc.last_operator();
79 ASSERT_TRUE(new_psop);
80 PDF_PSOP new_op = new_psop->GetOp();
81 EXPECT_EQ(item.op, new_op);
82 if (new_op == PSOP_CONST) {
83 float fv = new_psop->GetFloatValue();
84 if (word == "55") {
85 EXPECT_FLOAT_EQ(55.0f, fv);
86 } else if (word == "123.4") {
87 EXPECT_FLOAT_EQ(123.4f, fv);
88 } else if (word == "-5") {
89 EXPECT_FLOAT_EQ(-5.0f, fv);
90 } else if (word == "invalid") {
91 EXPECT_FLOAT_EQ(0.0f, fv);
92 } else {
93 NOTREACHED_NORETURN();
94 }
95 }
96 }
97 }
98
TEST(CPDFPSEngineTest,Basic)99 TEST(CPDFPSEngineTest, Basic) {
100 CPDF_PSEngine engine;
101
102 EXPECT_FLOAT_EQ(300.0f, DoOperator2(&engine, 100, 200, PSOP_ADD));
103 EXPECT_FLOAT_EQ(-50.0f, DoOperator2(&engine, 100, 150, PSOP_SUB));
104 EXPECT_FLOAT_EQ(600.0f, DoOperator2(&engine, 5, 120, PSOP_MUL));
105 EXPECT_FLOAT_EQ(1.5f, DoOperator2(&engine, 15, 10, PSOP_DIV));
106 EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 15, 10, PSOP_IDIV));
107 EXPECT_FLOAT_EQ(5.0f, DoOperator2(&engine, 15, 10, PSOP_MOD));
108 EXPECT_FLOAT_EQ(5.0f, DoOperator1(&engine, -5, PSOP_NEG));
109 EXPECT_FLOAT_EQ(5.0f, DoOperator1(&engine, -5, PSOP_ABS));
110 }
111
TEST(CPDFPSEngineTest,DivByZero)112 TEST(CPDFPSEngineTest, DivByZero) {
113 CPDF_PSEngine engine;
114
115 // Integer divide by zero is defined as resulting in 0.
116 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 100, 0.0, PSOP_IDIV));
117 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 100, 0.0, PSOP_MOD));
118
119 // floating divide by zero is defined as resulting in 0.
120 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 100, 0.0, PSOP_DIV));
121 }
122
TEST(CPDFPSEngineTest,Ceiling)123 TEST(CPDFPSEngineTest, Ceiling) {
124 CPDF_PSEngine engine;
125
126 // Smallest positive float value.
127 float min_float = std::numeric_limits<float>::min();
128 // Largest positive float value.
129 float max_float = std::numeric_limits<float>::max();
130 EXPECT_FLOAT_EQ(1.0f, DoOperator1(&engine, min_float, PSOP_CEILING));
131 EXPECT_FLOAT_EQ(max_float, DoOperator1(&engine, max_float, PSOP_CEILING));
132 EXPECT_FLOAT_EQ(0.0f, DoOperator1(&engine, -min_float, PSOP_CEILING));
133 EXPECT_FLOAT_EQ(-max_float, DoOperator1(&engine, -max_float, PSOP_CEILING));
134 EXPECT_FLOAT_EQ(0.0f, DoOperator1(&engine, -0.9f, PSOP_CEILING));
135 EXPECT_FLOAT_EQ(1.0f, DoOperator1(&engine, 0.0000000001f, PSOP_CEILING));
136 EXPECT_FLOAT_EQ(0.0f, DoOperator1(&engine, 0.0f, PSOP_CEILING));
137 EXPECT_FLOAT_EQ(3.0f, DoOperator1(&engine, 2.3f, PSOP_CEILING));
138 EXPECT_FLOAT_EQ(4.0f, DoOperator1(&engine, 3.8f, PSOP_CEILING));
139 EXPECT_FLOAT_EQ(6.0f, DoOperator1(&engine, 5.5f, PSOP_CEILING));
140 EXPECT_FLOAT_EQ(-2.0f, DoOperator1(&engine, -2.3f, PSOP_CEILING));
141 EXPECT_FLOAT_EQ(-3.0f, DoOperator1(&engine, -3.8f, PSOP_CEILING));
142 EXPECT_FLOAT_EQ(-5.0f, DoOperator1(&engine, -5.5f, PSOP_CEILING));
143 }
144
TEST(CPDFPSEngineTest,Floor)145 TEST(CPDFPSEngineTest, Floor) {
146 CPDF_PSEngine engine;
147
148 // Smallest positive float value.
149 float min_float = std::numeric_limits<float>::min();
150 // Largest positive float value.
151 float max_float = std::numeric_limits<float>::max();
152 EXPECT_FLOAT_EQ(0.0f, DoOperator1(&engine, min_float, PSOP_FLOOR));
153 EXPECT_FLOAT_EQ(max_float, DoOperator1(&engine, max_float, PSOP_FLOOR));
154 EXPECT_FLOAT_EQ(-1.0f, DoOperator1(&engine, -min_float, PSOP_FLOOR));
155 EXPECT_FLOAT_EQ(-max_float, DoOperator1(&engine, -max_float, PSOP_FLOOR));
156 EXPECT_FLOAT_EQ(5.0f, DoOperator1(&engine, 5.9f, PSOP_FLOOR));
157 EXPECT_FLOAT_EQ(-4.0f, DoOperator1(&engine, -4.0000000001f, PSOP_FLOOR));
158 EXPECT_FLOAT_EQ(0.0f, DoOperator1(&engine, 0.0f, PSOP_FLOOR));
159 EXPECT_FLOAT_EQ(-1.0f, DoOperator1(&engine, -0.9f, PSOP_FLOOR));
160 EXPECT_FLOAT_EQ(0.0f, DoOperator1(&engine, 0.0000000001f, PSOP_FLOOR));
161 EXPECT_FLOAT_EQ(0.0f, DoOperator1(&engine, 0.0f, PSOP_FLOOR));
162 EXPECT_FLOAT_EQ(2.0f, DoOperator1(&engine, 2.3f, PSOP_FLOOR));
163 EXPECT_FLOAT_EQ(3.0f, DoOperator1(&engine, 3.8f, PSOP_FLOOR));
164 EXPECT_FLOAT_EQ(5.0f, DoOperator1(&engine, 5.5f, PSOP_FLOOR));
165 EXPECT_FLOAT_EQ(-3.0f, DoOperator1(&engine, -2.3f, PSOP_FLOOR));
166 EXPECT_FLOAT_EQ(-4.0f, DoOperator1(&engine, -3.8f, PSOP_FLOOR));
167 EXPECT_FLOAT_EQ(-6.0f, DoOperator1(&engine, -5.5f, PSOP_FLOOR));
168 }
169
TEST(CPDFPSEngineTest,Round)170 TEST(CPDFPSEngineTest, Round) {
171 CPDF_PSEngine engine;
172
173 EXPECT_FLOAT_EQ(6.0f, DoOperator1(&engine, 5.9f, PSOP_ROUND));
174 EXPECT_FLOAT_EQ(-4.0f, DoOperator1(&engine, -4.0000000001f, PSOP_ROUND));
175 EXPECT_FLOAT_EQ(0.0f, DoOperator1(&engine, 0.0f, PSOP_ROUND));
176 EXPECT_FLOAT_EQ(-1.0f, DoOperator1(&engine, -0.9f, PSOP_ROUND));
177 EXPECT_FLOAT_EQ(0.0f, DoOperator1(&engine, 0.0000000001f, PSOP_ROUND));
178 EXPECT_FLOAT_EQ(0.0f, DoOperator1(&engine, 0.0f, PSOP_ROUND));
179 // Smallest positive float value.
180 float min_float = std::numeric_limits<float>::min();
181 // Largest positive float value.
182 float max_float = std::numeric_limits<float>::max();
183 EXPECT_FLOAT_EQ(0.0f, DoOperator1(&engine, min_float, PSOP_ROUND));
184 EXPECT_FLOAT_EQ(0.0f, DoOperator1(&engine, -min_float, PSOP_ROUND));
185 EXPECT_FLOAT_EQ(max_float, DoOperator1(&engine, max_float, PSOP_ROUND));
186 EXPECT_FLOAT_EQ(-max_float, DoOperator1(&engine, -max_float, PSOP_ROUND));
187 EXPECT_FLOAT_EQ(2.0f, DoOperator1(&engine, 2.3f, PSOP_ROUND));
188 EXPECT_FLOAT_EQ(4.0f, DoOperator1(&engine, 3.8f, PSOP_ROUND));
189 EXPECT_FLOAT_EQ(6.0f, DoOperator1(&engine, 5.5f, PSOP_ROUND));
190 EXPECT_FLOAT_EQ(-2.0f, DoOperator1(&engine, -2.3f, PSOP_ROUND));
191 EXPECT_FLOAT_EQ(-4.0f, DoOperator1(&engine, -3.8f, PSOP_ROUND));
192 EXPECT_FLOAT_EQ(-5.0f, DoOperator1(&engine, -5.5f, PSOP_ROUND));
193 }
194
TEST(CPDFPSEngineTest,Truncate)195 TEST(CPDFPSEngineTest, Truncate) {
196 CPDF_PSEngine engine;
197
198 EXPECT_FLOAT_EQ(0.0f, DoOperator1(&engine, -0.9f, PSOP_TRUNCATE));
199 EXPECT_FLOAT_EQ(0.0f, DoOperator1(&engine, 0.0000000001f, PSOP_TRUNCATE));
200 EXPECT_FLOAT_EQ(0.0f, DoOperator1(&engine, 0.0f, PSOP_TRUNCATE));
201 // Smallest positive float value.
202 float min_float = std::numeric_limits<float>::min();
203 EXPECT_FLOAT_EQ(0.0f, DoOperator1(&engine, min_float, PSOP_TRUNCATE));
204 EXPECT_FLOAT_EQ(0.0f, DoOperator1(&engine, -min_float, PSOP_TRUNCATE));
205 EXPECT_FLOAT_EQ(2.0f, DoOperator1(&engine, 2.3f, PSOP_TRUNCATE));
206 EXPECT_FLOAT_EQ(3.0f, DoOperator1(&engine, 3.8f, PSOP_TRUNCATE));
207 EXPECT_FLOAT_EQ(5.0f, DoOperator1(&engine, 5.5f, PSOP_TRUNCATE));
208 EXPECT_FLOAT_EQ(-2.0f, DoOperator1(&engine, -2.3f, PSOP_TRUNCATE));
209 EXPECT_FLOAT_EQ(-3.0f, DoOperator1(&engine, -3.8f, PSOP_TRUNCATE));
210 EXPECT_FLOAT_EQ(-5.0f, DoOperator1(&engine, -5.5f, PSOP_TRUNCATE));
211
212 // Truncate does not behave according to the PostScript Language Reference for
213 // values beyond the range of integers. This seems to match Acrobat's
214 // behavior. See https://crbug.com/pdfium/1314.
215 float max_int = static_cast<float>(std::numeric_limits<int>::max());
216 EXPECT_FLOAT_EQ(-max_int,
217 DoOperator1(&engine, max_int * -1.5f, PSOP_TRUNCATE));
218 }
219
TEST(CPDFPSEngineTest,Comparisons)220 TEST(CPDFPSEngineTest, Comparisons) {
221 CPDF_PSEngine engine;
222
223 EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 0.0f, 0.0f, PSOP_EQ));
224 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 0.0f, 1.0f, PSOP_EQ));
225 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 255.0f, 1.0f, PSOP_EQ));
226 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, -1.0f, 0.0f, PSOP_EQ));
227
228 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 0.0f, 0.0f, PSOP_NE));
229 EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 0.0f, 1.0f, PSOP_NE));
230 EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 255.0f, 1.0f, PSOP_NE));
231 EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, -1.0f, 0.0f, PSOP_NE));
232
233 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 0.0f, 0.0f, PSOP_GT));
234 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 0.0f, 1.0f, PSOP_GT));
235 EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 255.0f, 1.0f, PSOP_GT));
236 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, -1.0f, 0.0f, PSOP_GT));
237
238 EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 0.0f, 0.0f, PSOP_GE));
239 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 0.0f, 1.0f, PSOP_GE));
240 EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 255.0f, 1.0f, PSOP_GE));
241 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, -1.0f, 0.0f, PSOP_GE));
242
243 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 0.0f, 0.0f, PSOP_LT));
244 EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 0.0f, 1.0f, PSOP_LT));
245 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 255.0f, 1.0f, PSOP_LT));
246 EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, -1.0f, 0.0f, PSOP_LT));
247
248 EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 0.0f, 0.0f, PSOP_LE));
249 EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 0.0f, 1.0f, PSOP_LE));
250 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 255.0f, 1.0f, PSOP_LE));
251 EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, -1.0f, 0.0f, PSOP_LE));
252 }
253
TEST(CPDFPSEngineTest,Logic)254 TEST(CPDFPSEngineTest, Logic) {
255 CPDF_PSEngine engine;
256
257 EXPECT_FLOAT_EQ(1.0f, DoOperator0(&engine, PSOP_TRUE));
258 EXPECT_FLOAT_EQ(0.0f, DoOperator0(&engine, PSOP_FALSE));
259
260 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 0.0f, 0.0f, PSOP_AND));
261 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 0.0f, 1.0f, PSOP_AND));
262 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 1.0f, 0.0f, PSOP_AND));
263 EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 1.0f, 1.0f, PSOP_AND));
264
265 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 0.0f, 0.0f, PSOP_OR));
266 EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 0.0f, 1.0f, PSOP_OR));
267 EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 1.0f, 0.0f, PSOP_OR));
268 EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 1.0f, 1.0f, PSOP_OR));
269
270 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 0.0f, 0.0f, PSOP_XOR));
271 EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 0.0f, 1.0f, PSOP_XOR));
272 EXPECT_FLOAT_EQ(1.0f, DoOperator2(&engine, 1.0f, 0.0f, PSOP_XOR));
273 EXPECT_FLOAT_EQ(0.0f, DoOperator2(&engine, 1.0f, 1.0f, PSOP_XOR));
274
275 EXPECT_FLOAT_EQ(1.0f, DoOperator1(&engine, 0.0f, PSOP_NOT));
276 EXPECT_FLOAT_EQ(0.0f, DoOperator1(&engine, 1.0f, PSOP_NOT));
277 }
278
TEST(CPDFPSEngineTest,MathFunctions)279 TEST(CPDFPSEngineTest, MathFunctions) {
280 CPDF_PSEngine engine;
281
282 EXPECT_FLOAT_EQ(1.4142135f, DoOperator1(&engine, 2.0f, PSOP_SQRT));
283 EXPECT_FLOAT_EQ(0.8660254f, DoOperator1(&engine, 60.0f, PSOP_SIN));
284 EXPECT_FLOAT_EQ(0.5f, DoOperator1(&engine, 60.0f, PSOP_COS));
285 EXPECT_FLOAT_EQ(45.0f, DoOperator2(&engine, 1.0f, 1.0f, PSOP_ATAN));
286 EXPECT_FLOAT_EQ(1000.0f, DoOperator2(&engine, 10.0f, 3.0f, PSOP_EXP));
287 EXPECT_FLOAT_EQ(3.0f, DoOperator1(&engine, 1000.0f, PSOP_LOG));
288 EXPECT_FLOAT_EQ(2.302585f, DoOperator1(&engine, 10.0f, PSOP_LN));
289 }
290