1 // Copyright 2015 The Chromium 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 "pdf/pdf_transform.h"
6
7 #include "printing/units.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9 #include "ui/gfx/geometry/point_f.h"
10 #include "ui/gfx/geometry/rect.h"
11 #include "ui/gfx/geometry/size_f.h"
12
13 namespace chrome_pdf {
14
15 namespace {
16
17 constexpr float kDefaultWidth = 8.5 * printing::kPointsPerInch;
18 constexpr float kDefaultHeight = 11.0 * printing::kPointsPerInch;
19 constexpr float kDefaultRatio = kDefaultWidth / kDefaultHeight;
20 constexpr float kTolerance = 0.0001f;
21
ExpectDefaultPortraitBox(const PdfRectangle & box)22 void ExpectDefaultPortraitBox(const PdfRectangle& box) {
23 EXPECT_FLOAT_EQ(0, box.left);
24 EXPECT_FLOAT_EQ(0, box.bottom);
25 EXPECT_FLOAT_EQ(kDefaultWidth, box.right);
26 EXPECT_FLOAT_EQ(kDefaultHeight, box.top);
27 }
28
ExpectDefaultLandscapeBox(const PdfRectangle & box)29 void ExpectDefaultLandscapeBox(const PdfRectangle& box) {
30 EXPECT_FLOAT_EQ(0, box.left);
31 EXPECT_FLOAT_EQ(0, box.bottom);
32 EXPECT_FLOAT_EQ(kDefaultHeight, box.right);
33 EXPECT_FLOAT_EQ(kDefaultWidth, box.top);
34 }
35
ExpectBoxesAreEqual(const PdfRectangle & expected,const PdfRectangle & actual)36 void ExpectBoxesAreEqual(const PdfRectangle& expected,
37 const PdfRectangle& actual) {
38 EXPECT_FLOAT_EQ(expected.left, actual.left);
39 EXPECT_FLOAT_EQ(expected.bottom, actual.bottom);
40 EXPECT_FLOAT_EQ(expected.right, actual.right);
41 EXPECT_FLOAT_EQ(expected.top, actual.top);
42 }
43
InitializeBoxToInvalidValues(PdfRectangle * box)44 void InitializeBoxToInvalidValues(PdfRectangle* box) {
45 box->left = box->bottom = box->right = box->top = -1;
46 }
47
InitializeBoxToDefaultPortraitValues(PdfRectangle * box)48 void InitializeBoxToDefaultPortraitValues(PdfRectangle* box) {
49 box->left = 0;
50 box->bottom = 0;
51 box->right = kDefaultWidth;
52 box->top = kDefaultHeight;
53 }
54
InitializeBoxToDefaultLandscapeValue(PdfRectangle * box)55 void InitializeBoxToDefaultLandscapeValue(PdfRectangle* box) {
56 box->left = 0;
57 box->bottom = 0;
58 box->right = kDefaultHeight;
59 box->top = kDefaultWidth;
60 }
61
62 } // namespace
63
TEST(PdfTransformTest,CalculateScaleFactor)64 TEST(PdfTransformTest, CalculateScaleFactor) {
65 static constexpr gfx::SizeF kSize(kDefaultWidth, kDefaultHeight);
66 gfx::Rect rect(kDefaultWidth, kDefaultHeight);
67 float scale;
68
69 // 1:1
70 scale = CalculateScaleFactor(rect, kSize, false);
71 EXPECT_NEAR(1.0f, scale, kTolerance);
72 scale = CalculateScaleFactor(rect, kSize, true);
73 EXPECT_NEAR(kDefaultRatio, scale, kTolerance);
74
75 // 1:2
76 rect = gfx::Rect(kDefaultWidth / 2, kDefaultHeight / 2);
77 scale = CalculateScaleFactor(rect, kSize, false);
78 EXPECT_NEAR(0.5f, scale, kTolerance);
79 scale = CalculateScaleFactor(rect, kSize, true);
80 EXPECT_NEAR(kDefaultRatio / 2, scale, kTolerance);
81
82 // 3:1
83 rect = gfx::Rect(kDefaultWidth * 3, kDefaultHeight * 3);
84 scale = CalculateScaleFactor(rect, kSize, false);
85 EXPECT_NEAR(3.0f, scale, kTolerance);
86 scale = CalculateScaleFactor(rect, kSize, true);
87 EXPECT_NEAR(kDefaultRatio * 3, scale, kTolerance);
88
89 // 3:1, rotated.
90 rect = gfx::Rect(kDefaultHeight * 3, kDefaultWidth * 3);
91 scale = CalculateScaleFactor(rect, kSize, false);
92 EXPECT_NEAR(kDefaultRatio * 3, scale, kTolerance);
93 scale = CalculateScaleFactor(rect, kSize, true);
94 EXPECT_NEAR(3.0f, scale, kTolerance);
95
96 // Odd size
97 rect = gfx::Rect(10, 1000);
98 scale = CalculateScaleFactor(rect, kSize, false);
99 EXPECT_NEAR(0.01634f, scale, kTolerance);
100 scale = CalculateScaleFactor(rect, kSize, true);
101 EXPECT_NEAR(0.01263f, scale, kTolerance);
102 }
103
TEST(PdfTransformTest,SetDefaultClipBox)104 TEST(PdfTransformTest, SetDefaultClipBox) {
105 PdfRectangle box;
106
107 SetDefaultClipBox(false, &box);
108 ExpectDefaultPortraitBox(box);
109
110 SetDefaultClipBox(true, &box);
111 ExpectDefaultLandscapeBox(box);
112 }
113
TEST(PdfTransformTest,CalculateMediaBoxAndCropBox)114 TEST(PdfTransformTest, CalculateMediaBoxAndCropBox) {
115 PdfRectangle media_box;
116 PdfRectangle crop_box;
117
118 // Assume both boxes are there.
119 InitializeBoxToDefaultPortraitValues(&media_box);
120 InitializeBoxToDefaultLandscapeValue(&crop_box);
121 CalculateMediaBoxAndCropBox(true, true, true, &media_box, &crop_box);
122 ExpectDefaultPortraitBox(media_box);
123 ExpectDefaultLandscapeBox(crop_box);
124
125 // Assume both boxes are missing.
126 InitializeBoxToInvalidValues(&media_box);
127 InitializeBoxToInvalidValues(&crop_box);
128 CalculateMediaBoxAndCropBox(false, false, false, &media_box, &crop_box);
129 ExpectDefaultPortraitBox(media_box);
130 ExpectDefaultPortraitBox(crop_box);
131 CalculateMediaBoxAndCropBox(true, false, false, &media_box, &crop_box);
132 ExpectDefaultLandscapeBox(media_box);
133 ExpectDefaultLandscapeBox(crop_box);
134
135 // Assume crop box is missing.
136 constexpr PdfRectangle expected_box = {0, 0, 42, 420};
137 media_box = expected_box;
138 InitializeBoxToInvalidValues(&crop_box);
139 CalculateMediaBoxAndCropBox(false, true, false, &media_box, &crop_box);
140 ExpectBoxesAreEqual(expected_box, media_box);
141 ExpectBoxesAreEqual(expected_box, crop_box);
142
143 // Assume media box is missing.
144 InitializeBoxToInvalidValues(&media_box);
145 CalculateMediaBoxAndCropBox(false, false, true, &media_box, &crop_box);
146 ExpectBoxesAreEqual(expected_box, media_box);
147 ExpectBoxesAreEqual(expected_box, crop_box);
148 }
149
TEST(PdfTransformTest,CalculateClipBoxBoundary)150 TEST(PdfTransformTest, CalculateClipBoxBoundary) {
151 PdfRectangle media_box;
152 PdfRectangle crop_box;
153 PdfRectangle result;
154
155 // media box and crop box are the same.
156 InitializeBoxToDefaultPortraitValues(&media_box);
157 InitializeBoxToDefaultPortraitValues(&crop_box);
158 result = CalculateClipBoxBoundary(media_box, crop_box);
159 ExpectDefaultPortraitBox(result);
160
161 // media box is portrait and crop box is landscape.
162 InitializeBoxToDefaultLandscapeValue(&crop_box);
163 result = CalculateClipBoxBoundary(media_box, crop_box);
164 EXPECT_FLOAT_EQ(0, result.left);
165 EXPECT_FLOAT_EQ(0, result.bottom);
166 EXPECT_FLOAT_EQ(kDefaultWidth, result.right);
167 EXPECT_FLOAT_EQ(kDefaultWidth, result.top);
168
169 // crop box is smaller than media box.
170 crop_box.left = 0;
171 crop_box.bottom = 0;
172 crop_box.right = 100;
173 crop_box.top = 200;
174 result = CalculateClipBoxBoundary(media_box, crop_box);
175 EXPECT_FLOAT_EQ(0, result.left);
176 EXPECT_FLOAT_EQ(0, result.bottom);
177 EXPECT_FLOAT_EQ(100, result.right);
178 EXPECT_FLOAT_EQ(200, result.top);
179
180 // crop box is smaller than the media box in one dimension and longer in the
181 // other.
182 crop_box.left = 0;
183 crop_box.bottom = 0;
184 crop_box.right = 100;
185 crop_box.top = 2000;
186 result = CalculateClipBoxBoundary(media_box, crop_box);
187 EXPECT_FLOAT_EQ(0, result.left);
188 EXPECT_FLOAT_EQ(0, result.bottom);
189 EXPECT_FLOAT_EQ(100, result.right);
190 EXPECT_FLOAT_EQ(kDefaultHeight, result.top);
191 }
192
TEST(PdfTransformTest,CalculateScaledClipBoxOffset)193 TEST(PdfTransformTest, CalculateScaledClipBoxOffset) {
194 constexpr gfx::Rect rect(kDefaultWidth, kDefaultHeight);
195 PdfRectangle clip_box;
196 gfx::PointF offset;
197
198 // |rect| and |clip_box| are the same size.
199 InitializeBoxToDefaultPortraitValues(&clip_box);
200 offset = CalculateScaledClipBoxOffset(rect, clip_box);
201 EXPECT_FLOAT_EQ(0, offset.x());
202 EXPECT_FLOAT_EQ(0, offset.y());
203
204 // |rect| is larger than |clip_box|.
205 clip_box.top /= 2;
206 clip_box.right /= 4;
207 offset = CalculateScaledClipBoxOffset(rect, clip_box);
208 EXPECT_FLOAT_EQ(229.5f, offset.x());
209 EXPECT_FLOAT_EQ(198, offset.y());
210 }
211
TEST(PdfTransformTest,CalculateNonScaledClipBoxOffset)212 TEST(PdfTransformTest, CalculateNonScaledClipBoxOffset) {
213 int page_width = kDefaultWidth;
214 int page_height = kDefaultHeight;
215 PdfRectangle clip_box;
216 gfx::PointF offset;
217
218 // |rect|, page size and |clip_box| are the same.
219 InitializeBoxToDefaultPortraitValues(&clip_box);
220 offset =
221 CalculateNonScaledClipBoxOffset(0, page_width, page_height, clip_box);
222 EXPECT_FLOAT_EQ(0, offset.x());
223 EXPECT_FLOAT_EQ(0, offset.y());
224 offset =
225 CalculateNonScaledClipBoxOffset(1, page_width, page_height, clip_box);
226 EXPECT_FLOAT_EQ(0, offset.x());
227 EXPECT_FLOAT_EQ(0, offset.y());
228 offset =
229 CalculateNonScaledClipBoxOffset(2, page_width, page_height, clip_box);
230 EXPECT_FLOAT_EQ(0, offset.x());
231 EXPECT_FLOAT_EQ(0, offset.y());
232 offset =
233 CalculateNonScaledClipBoxOffset(3, page_width, page_height, clip_box);
234 EXPECT_FLOAT_EQ(180, offset.x());
235 EXPECT_FLOAT_EQ(-180, offset.y());
236
237 // Smaller |clip_box|.
238 clip_box.top /= 4;
239 clip_box.right /= 2;
240 offset =
241 CalculateNonScaledClipBoxOffset(0, page_width, page_height, clip_box);
242 EXPECT_FLOAT_EQ(0, offset.x());
243 EXPECT_FLOAT_EQ(594, offset.y());
244 offset =
245 CalculateNonScaledClipBoxOffset(1, page_width, page_height, clip_box);
246 EXPECT_FLOAT_EQ(0, offset.x());
247 EXPECT_FLOAT_EQ(0, offset.y());
248 offset =
249 CalculateNonScaledClipBoxOffset(2, page_width, page_height, clip_box);
250 EXPECT_FLOAT_EQ(306, offset.x());
251 EXPECT_FLOAT_EQ(0, offset.y());
252 offset =
253 CalculateNonScaledClipBoxOffset(3, page_width, page_height, clip_box);
254 EXPECT_FLOAT_EQ(486, offset.x());
255 EXPECT_FLOAT_EQ(414, offset.y());
256
257 // Larger page size.
258 InitializeBoxToDefaultPortraitValues(&clip_box);
259 page_width += 10;
260 page_height += 20;
261 offset =
262 CalculateNonScaledClipBoxOffset(0, page_width, page_height, clip_box);
263 EXPECT_FLOAT_EQ(0, offset.x());
264 EXPECT_FLOAT_EQ(20, offset.y());
265 offset =
266 CalculateNonScaledClipBoxOffset(1, page_width, page_height, clip_box);
267 EXPECT_FLOAT_EQ(0, offset.x());
268 EXPECT_FLOAT_EQ(0, offset.y());
269 offset =
270 CalculateNonScaledClipBoxOffset(2, page_width, page_height, clip_box);
271 EXPECT_FLOAT_EQ(10, offset.x());
272 EXPECT_FLOAT_EQ(0, offset.y());
273 offset =
274 CalculateNonScaledClipBoxOffset(3, page_width, page_height, clip_box);
275 EXPECT_FLOAT_EQ(200, offset.x());
276 EXPECT_FLOAT_EQ(-170, offset.y());
277 }
278
279 // https://crbug.com/491160 and https://crbug.com/588757
TEST(PdfTransformTest,ReversedMediaBox)280 TEST(PdfTransformTest, ReversedMediaBox) {
281 int page_width = kDefaultWidth;
282 int page_height = kDefaultHeight;
283 constexpr gfx::Rect rect(kDefaultWidth, kDefaultHeight);
284 PdfRectangle clip_box;
285 gfx::PointF offset;
286
287 constexpr PdfRectangle expected_media_box_b491160 = {0, -792, 612, 0};
288 PdfRectangle media_box_b491160 = {0, 0, 612, -792};
289 CalculateMediaBoxAndCropBox(false, true, false, &media_box_b491160,
290 &clip_box);
291 ExpectBoxesAreEqual(expected_media_box_b491160, media_box_b491160);
292 ExpectBoxesAreEqual(expected_media_box_b491160, clip_box);
293
294 offset = CalculateScaledClipBoxOffset(rect, media_box_b491160);
295 EXPECT_FLOAT_EQ(0, offset.x());
296 EXPECT_FLOAT_EQ(792, offset.y());
297
298 offset = CalculateNonScaledClipBoxOffset(0, page_width, page_height,
299 media_box_b491160);
300 EXPECT_FLOAT_EQ(0, offset.x());
301 EXPECT_FLOAT_EQ(792, offset.y());
302
303 PdfRectangle media_box_b588757 = {0, 792, 612, 0};
304 CalculateMediaBoxAndCropBox(false, true, false, &media_box_b588757,
305 &clip_box);
306 ExpectDefaultPortraitBox(media_box_b588757);
307 ExpectDefaultPortraitBox(clip_box);
308
309 offset = CalculateScaledClipBoxOffset(rect, clip_box);
310 EXPECT_FLOAT_EQ(0, offset.x());
311 EXPECT_FLOAT_EQ(0, offset.y());
312
313 offset =
314 CalculateNonScaledClipBoxOffset(0, page_width, page_height, clip_box);
315 EXPECT_FLOAT_EQ(0, offset.x());
316 EXPECT_FLOAT_EQ(0, offset.y());
317
318 PdfRectangle media_box_left_right_flipped = {612, 792, 0, 0};
319 CalculateMediaBoxAndCropBox(false, true, false, &media_box_left_right_flipped,
320 &clip_box);
321 ExpectDefaultPortraitBox(media_box_left_right_flipped);
322 ExpectDefaultPortraitBox(clip_box);
323
324 offset = CalculateScaledClipBoxOffset(rect, clip_box);
325 EXPECT_FLOAT_EQ(0, offset.x());
326 EXPECT_FLOAT_EQ(0, offset.y());
327
328 offset =
329 CalculateNonScaledClipBoxOffset(0, page_width, page_height, clip_box);
330 EXPECT_FLOAT_EQ(0, offset.x());
331 EXPECT_FLOAT_EQ(0, offset.y());
332 }
333
334 } // namespace chrome_pdf
335