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