1 // Copyright 2017 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 "components/viz/common/frame_sinks/copy_output_util.h"
6
7 #include <limits>
8
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "ui/gfx/geometry/rect.h"
11 #include "ui/gfx/geometry/vector2d.h"
12
13 namespace viz {
14 namespace copy_output {
15
16 namespace {
17
18 // Some very large integers that should be big enough to trigger overflow
19 // conditions, if the implementation is doing bad math.
20 constexpr int kMaxInt = std::numeric_limits<int>::max();
21 constexpr int kMaxEvenInt = kMaxInt - 1;
22
23 // These are all equivalent to a scale ratio of 1:1.
24 constexpr gfx::Vector2d kNonScalingVectors[5][2] = {
25 {gfx::Vector2d(1, 1), gfx::Vector2d(1, 1)},
26 {gfx::Vector2d(42, 1), gfx::Vector2d(42, 1)},
27 {gfx::Vector2d(1, 42), gfx::Vector2d(1, 42)},
28 {gfx::Vector2d(kMaxInt, 1), gfx::Vector2d(kMaxInt, 1)},
29 {gfx::Vector2d(1, kMaxInt), gfx::Vector2d(1, kMaxInt)},
30 };
31
32 // These are all equivalent to a scale ratio of 1:2 in the X direction.
33 constexpr gfx::Vector2d kDoublingXVectors[4][2] = {
34 {gfx::Vector2d(1, 1), gfx::Vector2d(2, 1)},
35 {gfx::Vector2d(21, 1), gfx::Vector2d(42, 1)},
36 {gfx::Vector2d(kMaxEvenInt / 2, 1), gfx::Vector2d(kMaxEvenInt, 1)},
37 {gfx::Vector2d(kMaxEvenInt / 2, kMaxInt),
38 gfx::Vector2d(kMaxEvenInt, kMaxInt)},
39 };
40
41 // These are all equivalent to a scale ratio of 1:2 in the Y direction.
42 constexpr gfx::Vector2d kDoublingYVectors[4][2] = {
43 {gfx::Vector2d(1, 1), gfx::Vector2d(1, 2)},
44 {gfx::Vector2d(1, 55), gfx::Vector2d(1, 110)},
45 {gfx::Vector2d(1, kMaxEvenInt / 2), gfx::Vector2d(1, kMaxEvenInt)},
46 {gfx::Vector2d(kMaxInt, kMaxEvenInt / 2),
47 gfx::Vector2d(kMaxInt, kMaxEvenInt)},
48 };
49
50 // These are all equivalent to a scale ratio of 2:1 in the X direction.
51 constexpr gfx::Vector2d kHalvingXVectors[4][2] = {
52 {gfx::Vector2d(2, 1), gfx::Vector2d(1, 1)},
53 {gfx::Vector2d(42, 1), gfx::Vector2d(21, 1)},
54 {gfx::Vector2d(kMaxEvenInt, 1), gfx::Vector2d(kMaxEvenInt / 2, 1)},
55 {gfx::Vector2d(kMaxEvenInt, kMaxInt),
56 gfx::Vector2d(kMaxEvenInt / 2, kMaxInt)},
57 };
58
59 // These are all equivalent to a scale ratio of 2:1 in the Y direction.
60 constexpr gfx::Vector2d kHalvingYVectors[4][2] = {
61 {gfx::Vector2d(1, 2), gfx::Vector2d(1, 1)},
62 {gfx::Vector2d(1, 110), gfx::Vector2d(1, 55)},
63 {gfx::Vector2d(1, kMaxEvenInt), gfx::Vector2d(1, kMaxEvenInt / 2)},
64 {gfx::Vector2d(kMaxInt, kMaxEvenInt),
65 gfx::Vector2d(kMaxInt, kMaxEvenInt / 2)},
66 };
67
TEST(CopyOutputUtil,ComputesValidResultRects)68 TEST(CopyOutputUtil, ComputesValidResultRects) {
69 for (const gfx::Vector2d* v : kNonScalingVectors) {
70 SCOPED_TRACE(::testing::Message()
71 << "v[0]=" << v[0].ToString() << ", v[1]=" << v[1].ToString());
72 EXPECT_EQ(gfx::Rect(1, 2, 3, 4),
73 ComputeResultRect(gfx::Rect(1, 2, 3, 4), v[0], v[1]));
74 EXPECT_EQ(gfx::Rect(-1, 2, 3, 4),
75 ComputeResultRect(gfx::Rect(-1, 2, 3, 4), v[0], v[1]));
76 EXPECT_EQ(gfx::Rect(1, -2, 3, 4),
77 ComputeResultRect(gfx::Rect(1, -2, 3, 4), v[0], v[1]));
78 }
79 for (const gfx::Vector2d* v : kDoublingXVectors) {
80 SCOPED_TRACE(::testing::Message()
81 << "v[0]=" << v[0].ToString() << ", v[1]=" << v[1].ToString());
82 EXPECT_EQ(gfx::Rect(2, 2, 6, 4),
83 ComputeResultRect(gfx::Rect(1, 2, 3, 4), v[0], v[1]));
84 EXPECT_EQ(gfx::Rect(-2, 2, 6, 4),
85 ComputeResultRect(gfx::Rect(-1, 2, 3, 4), v[0], v[1]));
86 EXPECT_EQ(gfx::Rect(2, -2, 6, 4),
87 ComputeResultRect(gfx::Rect(1, -2, 3, 4), v[0], v[1]));
88 }
89 for (const gfx::Vector2d* v : kDoublingYVectors) {
90 SCOPED_TRACE(::testing::Message()
91 << "v[0]=" << v[0].ToString() << ", v[1]=" << v[1].ToString());
92 EXPECT_EQ(gfx::Rect(1, 4, 3, 8),
93 ComputeResultRect(gfx::Rect(1, 2, 3, 4), v[0], v[1]));
94 EXPECT_EQ(gfx::Rect(-1, 4, 3, 8),
95 ComputeResultRect(gfx::Rect(-1, 2, 3, 4), v[0], v[1]));
96 EXPECT_EQ(gfx::Rect(1, -4, 3, 8),
97 ComputeResultRect(gfx::Rect(1, -2, 3, 4), v[0], v[1]));
98 }
99 for (const gfx::Vector2d* v : kHalvingXVectors) {
100 SCOPED_TRACE(::testing::Message()
101 << "v[0]=" << v[0].ToString() << ", v[1]=" << v[1].ToString());
102 EXPECT_EQ(gfx::Rect(1, 2, 3, 4),
103 ComputeResultRect(gfx::Rect(2, 2, 6, 4), v[0], v[1]));
104 EXPECT_EQ(gfx::Rect(1, 2, 4, 4),
105 ComputeResultRect(gfx::Rect(3, 2, 6, 4), v[0], v[1]));
106 EXPECT_EQ(gfx::Rect(0, 2, 4, 4),
107 ComputeResultRect(gfx::Rect(1, 2, 6, 4), v[0], v[1]));
108 EXPECT_EQ(gfx::Rect(1, 2, 4, 4),
109 ComputeResultRect(gfx::Rect(2, 2, 7, 4), v[0], v[1]));
110 EXPECT_EQ(gfx::Rect(1, 2, 3, 4),
111 ComputeResultRect(gfx::Rect(2, 2, 5, 4), v[0], v[1]));
112 }
113 for (const gfx::Vector2d* v : kHalvingYVectors) {
114 SCOPED_TRACE(::testing::Message()
115 << "v[0]=" << v[0].ToString() << ", v[1]=" << v[1].ToString());
116 EXPECT_EQ(gfx::Rect(2, 1, 4, 3),
117 ComputeResultRect(gfx::Rect(2, 2, 4, 6), v[0], v[1]));
118 EXPECT_EQ(gfx::Rect(2, 1, 4, 4),
119 ComputeResultRect(gfx::Rect(2, 3, 4, 6), v[0], v[1]));
120 EXPECT_EQ(gfx::Rect(2, 0, 4, 4),
121 ComputeResultRect(gfx::Rect(2, 1, 4, 6), v[0], v[1]));
122 EXPECT_EQ(gfx::Rect(2, 1, 4, 4),
123 ComputeResultRect(gfx::Rect(2, 2, 4, 7), v[0], v[1]));
124 EXPECT_EQ(gfx::Rect(2, 1, 4, 3),
125 ComputeResultRect(gfx::Rect(2, 2, 4, 5), v[0], v[1]));
126 }
127
128 // Scale 3:2 in the X direction and 7:3 in the Y direction.
129 constexpr gfx::Vector2d kWeirdScaleFrom = gfx::Vector2d(3, 7);
130 constexpr gfx::Vector2d kWeirdScaleTo = gfx::Vector2d(2, 3);
131 EXPECT_EQ(
132 gfx::Rect(0, 0, 2, 2),
133 ComputeResultRect(gfx::Rect(1, 1, 1, 2), kWeirdScaleFrom, kWeirdScaleTo));
134 EXPECT_EQ(gfx::Rect(-1, -1, 1, 2),
135 ComputeResultRect(gfx::Rect(-1, -1, 1, 2), kWeirdScaleFrom,
136 kWeirdScaleTo));
137 EXPECT_EQ(
138 gfx::Rect(2, 3, 2, 3),
139 ComputeResultRect(gfx::Rect(3, 7, 3, 7), kWeirdScaleFrom, kWeirdScaleTo));
140 EXPECT_EQ(gfx::Rect(-2, -3, 4, 6),
141 ComputeResultRect(gfx::Rect(-3, -7, 6, 14), kWeirdScaleFrom,
142 kWeirdScaleTo));
143 int x = 1 << 24;
144 int y = 1 << 25;
145 int w = 1 << 15;
146 int h = 1 << 16;
147 EXPECT_EQ(
148 gfx::Rect(x * kWeirdScaleTo.x() / kWeirdScaleFrom.x(),
149 y * kWeirdScaleTo.y() / kWeirdScaleFrom.y(),
150 (x + w) * kWeirdScaleTo.x() / kWeirdScaleFrom.x() -
151 x * kWeirdScaleTo.x() / kWeirdScaleFrom.x(),
152 (y + h) * kWeirdScaleTo.y() / kWeirdScaleFrom.y() -
153 y * kWeirdScaleTo.y() / kWeirdScaleFrom.y() + 1),
154 ComputeResultRect(gfx::Rect(x, y, w, h), kWeirdScaleFrom, kWeirdScaleTo));
155 x = -(1 << 24);
156 y = -(1 << 25);
157 EXPECT_EQ(
158 gfx::Rect(x * kWeirdScaleTo.x() / kWeirdScaleFrom.x() - 1,
159 y * kWeirdScaleTo.y() / kWeirdScaleFrom.y() - 1,
160 (x + w) * kWeirdScaleTo.x() / kWeirdScaleFrom.x() -
161 x * kWeirdScaleTo.x() / kWeirdScaleFrom.x() + 1,
162 (y + h) * kWeirdScaleTo.y() / kWeirdScaleFrom.y() -
163 y * kWeirdScaleTo.y() / kWeirdScaleFrom.y() + 1),
164 ComputeResultRect(gfx::Rect(x, y, w, h), kWeirdScaleFrom, kWeirdScaleTo));
165 }
166
TEST(CopyOutputUtil,IdentifiesUnreasonableResultRects)167 TEST(CopyOutputUtil, IdentifiesUnreasonableResultRects) {
168 // When the scale ratio is too great for even a 1x1 rect to be scaled:
169 EXPECT_EQ(gfx::Rect(),
170 ComputeResultRect(gfx::Rect(1, 1, 1, 1), gfx::Vector2d(1, 1),
171 gfx::Vector2d(1 << 30, 1)));
172 EXPECT_EQ(gfx::Rect(),
173 ComputeResultRect(gfx::Rect(1, 1, 1, 1), gfx::Vector2d(1, 1),
174 gfx::Vector2d(1, 1 << 30)));
175 EXPECT_EQ(gfx::Rect(),
176 ComputeResultRect(gfx::Rect(1, 1, 1, 1), gfx::Vector2d(1, 1),
177 gfx::Vector2d(1 << 30, 1 << 30)));
178
179 // When the rect and scale ratio are large, but produce unreasonable results:
180 EXPECT_EQ(gfx::Rect(), ComputeResultRect(gfx::Rect(0, 0, 1 << 12, 1 << 13),
181 gfx::Vector2d(1, 1),
182 gfx::Vector2d(1 << 4, 1 << 3)));
183 EXPECT_EQ(gfx::Rect(), ComputeResultRect(gfx::Rect(1 << 20, 1 << 21, 1, 1),
184 gfx::Vector2d(1, 1),
185 gfx::Vector2d(1 << 4, 1 << 3)));
186 EXPECT_EQ(
187 gfx::Rect(),
188 ComputeResultRect(gfx::Rect(-(1 << 20), -(1 << 21), 1, 1),
189 gfx::Vector2d(1, 1), gfx::Vector2d(1 << 4, 1 << 3)));
190
191 // Boundary condition: Right on the edge of "unreasonable."
192 EXPECT_EQ(gfx::Rect((1 << 9) * ((1 << 15) - 1), 1, (1 << 15) - 1, 1),
193 ComputeResultRect(gfx::Rect(1 << 9, 1, 1, 1), gfx::Vector2d(1, 1),
194 gfx::Vector2d((1 << 15) - 1, 1)));
195 EXPECT_EQ(
196 gfx::Rect(-(1 << 9) * ((1 << 15) - 1), 1, (1 << 15) - 1, 1),
197 ComputeResultRect(gfx::Rect(-(1 << 9), 1, 1, 1), gfx::Vector2d(1, 1),
198 gfx::Vector2d((1 << 15) - 1, 1)));
199 EXPECT_EQ(gfx::Rect(1, (1 << 9) * ((1 << 15) - 1), 1, (1 << 15) - 1),
200 ComputeResultRect(gfx::Rect(1, 1 << 9, 1, 1), gfx::Vector2d(1, 1),
201 gfx::Vector2d(1, (1 << 15) - 1)));
202 EXPECT_EQ(
203 gfx::Rect(1, -(1 << 9) * ((1 << 15) - 1), 1, (1 << 15) - 1),
204 ComputeResultRect(gfx::Rect(1, -(1 << 9), 1, 1), gfx::Vector2d(1, 1),
205 gfx::Vector2d(1, (1 << 15) - 1)));
206 }
207
208 } // namespace
209
210 } // namespace copy_output
211 } // namespace viz
212