blob: bf82eaa463de4be162a9a4569e8b4dcc0b1c9922 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/viz/common/frame_sinks/copy_output_util.h"
#include <limits>
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/vector2d.h"
namespace viz {
namespace copy_output {
namespace {
// Some very large integers that should be big enough to trigger overflow
// conditions, if the implementation is doing bad math.
constexpr int kMaxInt = std::numeric_limits<int>::max();
constexpr int kMaxEvenInt = kMaxInt - 1;
// These are all equivalent to a scale ratio of 1:1.
constexpr gfx::Vector2d kNonScalingVectors[5][2] = {
{gfx::Vector2d(1, 1), gfx::Vector2d(1, 1)},
{gfx::Vector2d(42, 1), gfx::Vector2d(42, 1)},
{gfx::Vector2d(1, 42), gfx::Vector2d(1, 42)},
{gfx::Vector2d(kMaxInt, 1), gfx::Vector2d(kMaxInt, 1)},
{gfx::Vector2d(1, kMaxInt), gfx::Vector2d(1, kMaxInt)},
};
// These are all equivalent to a scale ratio of 1:2 in the X direction.
constexpr gfx::Vector2d kDoublingXVectors[4][2] = {
{gfx::Vector2d(1, 1), gfx::Vector2d(2, 1)},
{gfx::Vector2d(21, 1), gfx::Vector2d(42, 1)},
{gfx::Vector2d(kMaxEvenInt / 2, 1), gfx::Vector2d(kMaxEvenInt, 1)},
{gfx::Vector2d(kMaxEvenInt / 2, kMaxInt),
gfx::Vector2d(kMaxEvenInt, kMaxInt)},
};
// These are all equivalent to a scale ratio of 1:2 in the Y direction.
constexpr gfx::Vector2d kDoublingYVectors[4][2] = {
{gfx::Vector2d(1, 1), gfx::Vector2d(1, 2)},
{gfx::Vector2d(1, 55), gfx::Vector2d(1, 110)},
{gfx::Vector2d(1, kMaxEvenInt / 2), gfx::Vector2d(1, kMaxEvenInt)},
{gfx::Vector2d(kMaxInt, kMaxEvenInt / 2),
gfx::Vector2d(kMaxInt, kMaxEvenInt)},
};
// These are all equivalent to a scale ratio of 2:1 in the X direction.
constexpr gfx::Vector2d kHalvingXVectors[4][2] = {
{gfx::Vector2d(2, 1), gfx::Vector2d(1, 1)},
{gfx::Vector2d(42, 1), gfx::Vector2d(21, 1)},
{gfx::Vector2d(kMaxEvenInt, 1), gfx::Vector2d(kMaxEvenInt / 2, 1)},
{gfx::Vector2d(kMaxEvenInt, kMaxInt),
gfx::Vector2d(kMaxEvenInt / 2, kMaxInt)},
};
// These are all equivalent to a scale ratio of 2:1 in the Y direction.
constexpr gfx::Vector2d kHalvingYVectors[4][2] = {
{gfx::Vector2d(1, 2), gfx::Vector2d(1, 1)},
{gfx::Vector2d(1, 110), gfx::Vector2d(1, 55)},
{gfx::Vector2d(1, kMaxEvenInt), gfx::Vector2d(1, kMaxEvenInt / 2)},
{gfx::Vector2d(kMaxInt, kMaxEvenInt),
gfx::Vector2d(kMaxInt, kMaxEvenInt / 2)},
};
TEST(CopyOutputUtil, ComputesValidResultRects) {
for (const gfx::Vector2d* v : kNonScalingVectors) {
SCOPED_TRACE(::testing::Message()
<< "v[0]=" << v[0].ToString() << ", v[1]=" << v[1].ToString());
EXPECT_EQ(gfx::Rect(1, 2, 3, 4),
ComputeResultRect(gfx::Rect(1, 2, 3, 4), v[0], v[1]));
EXPECT_EQ(gfx::Rect(-1, 2, 3, 4),
ComputeResultRect(gfx::Rect(-1, 2, 3, 4), v[0], v[1]));
EXPECT_EQ(gfx::Rect(1, -2, 3, 4),
ComputeResultRect(gfx::Rect(1, -2, 3, 4), v[0], v[1]));
}
for (const gfx::Vector2d* v : kDoublingXVectors) {
SCOPED_TRACE(::testing::Message()
<< "v[0]=" << v[0].ToString() << ", v[1]=" << v[1].ToString());
EXPECT_EQ(gfx::Rect(2, 2, 6, 4),
ComputeResultRect(gfx::Rect(1, 2, 3, 4), v[0], v[1]));
EXPECT_EQ(gfx::Rect(-2, 2, 6, 4),
ComputeResultRect(gfx::Rect(-1, 2, 3, 4), v[0], v[1]));
EXPECT_EQ(gfx::Rect(2, -2, 6, 4),
ComputeResultRect(gfx::Rect(1, -2, 3, 4), v[0], v[1]));
}
for (const gfx::Vector2d* v : kDoublingYVectors) {
SCOPED_TRACE(::testing::Message()
<< "v[0]=" << v[0].ToString() << ", v[1]=" << v[1].ToString());
EXPECT_EQ(gfx::Rect(1, 4, 3, 8),
ComputeResultRect(gfx::Rect(1, 2, 3, 4), v[0], v[1]));
EXPECT_EQ(gfx::Rect(-1, 4, 3, 8),
ComputeResultRect(gfx::Rect(-1, 2, 3, 4), v[0], v[1]));
EXPECT_EQ(gfx::Rect(1, -4, 3, 8),
ComputeResultRect(gfx::Rect(1, -2, 3, 4), v[0], v[1]));
}
for (const gfx::Vector2d* v : kHalvingXVectors) {
SCOPED_TRACE(::testing::Message()
<< "v[0]=" << v[0].ToString() << ", v[1]=" << v[1].ToString());
EXPECT_EQ(gfx::Rect(1, 2, 3, 4),
ComputeResultRect(gfx::Rect(2, 2, 6, 4), v[0], v[1]));
EXPECT_EQ(gfx::Rect(1, 2, 4, 4),
ComputeResultRect(gfx::Rect(3, 2, 6, 4), v[0], v[1]));
EXPECT_EQ(gfx::Rect(0, 2, 4, 4),
ComputeResultRect(gfx::Rect(1, 2, 6, 4), v[0], v[1]));
EXPECT_EQ(gfx::Rect(1, 2, 4, 4),
ComputeResultRect(gfx::Rect(2, 2, 7, 4), v[0], v[1]));
EXPECT_EQ(gfx::Rect(1, 2, 3, 4),
ComputeResultRect(gfx::Rect(2, 2, 5, 4), v[0], v[1]));
}
for (const gfx::Vector2d* v : kHalvingYVectors) {
SCOPED_TRACE(::testing::Message()
<< "v[0]=" << v[0].ToString() << ", v[1]=" << v[1].ToString());
EXPECT_EQ(gfx::Rect(2, 1, 4, 3),
ComputeResultRect(gfx::Rect(2, 2, 4, 6), v[0], v[1]));
EXPECT_EQ(gfx::Rect(2, 1, 4, 4),
ComputeResultRect(gfx::Rect(2, 3, 4, 6), v[0], v[1]));
EXPECT_EQ(gfx::Rect(2, 0, 4, 4),
ComputeResultRect(gfx::Rect(2, 1, 4, 6), v[0], v[1]));
EXPECT_EQ(gfx::Rect(2, 1, 4, 4),
ComputeResultRect(gfx::Rect(2, 2, 4, 7), v[0], v[1]));
EXPECT_EQ(gfx::Rect(2, 1, 4, 3),
ComputeResultRect(gfx::Rect(2, 2, 4, 5), v[0], v[1]));
}
// Scale 3:2 in the X direction and 7:3 in the Y direction.
constexpr gfx::Vector2d kWeirdScaleFrom = gfx::Vector2d(3, 7);
constexpr gfx::Vector2d kWeirdScaleTo = gfx::Vector2d(2, 3);
EXPECT_EQ(
gfx::Rect(0, 0, 2, 2),
ComputeResultRect(gfx::Rect(1, 1, 1, 2), kWeirdScaleFrom, kWeirdScaleTo));
EXPECT_EQ(gfx::Rect(-1, -1, 1, 2),
ComputeResultRect(gfx::Rect(-1, -1, 1, 2), kWeirdScaleFrom,
kWeirdScaleTo));
EXPECT_EQ(
gfx::Rect(2, 3, 2, 3),
ComputeResultRect(gfx::Rect(3, 7, 3, 7), kWeirdScaleFrom, kWeirdScaleTo));
EXPECT_EQ(gfx::Rect(-2, -3, 4, 6),
ComputeResultRect(gfx::Rect(-3, -7, 6, 14), kWeirdScaleFrom,
kWeirdScaleTo));
int x = 1 << 24;
int y = 1 << 25;
int w = 1 << 15;
int h = 1 << 16;
EXPECT_EQ(
gfx::Rect(x * kWeirdScaleTo.x() / kWeirdScaleFrom.x(),
y * kWeirdScaleTo.y() / kWeirdScaleFrom.y(),
(x + w) * kWeirdScaleTo.x() / kWeirdScaleFrom.x() -
x * kWeirdScaleTo.x() / kWeirdScaleFrom.x(),
(y + h) * kWeirdScaleTo.y() / kWeirdScaleFrom.y() -
y * kWeirdScaleTo.y() / kWeirdScaleFrom.y() + 1),
ComputeResultRect(gfx::Rect(x, y, w, h), kWeirdScaleFrom, kWeirdScaleTo));
x = -(1 << 24);
y = -(1 << 25);
EXPECT_EQ(
gfx::Rect(x * kWeirdScaleTo.x() / kWeirdScaleFrom.x() - 1,
y * kWeirdScaleTo.y() / kWeirdScaleFrom.y() - 1,
(x + w) * kWeirdScaleTo.x() / kWeirdScaleFrom.x() -
x * kWeirdScaleTo.x() / kWeirdScaleFrom.x() + 1,
(y + h) * kWeirdScaleTo.y() / kWeirdScaleFrom.y() -
y * kWeirdScaleTo.y() / kWeirdScaleFrom.y() + 1),
ComputeResultRect(gfx::Rect(x, y, w, h), kWeirdScaleFrom, kWeirdScaleTo));
}
TEST(CopyOutputUtil, IdentifiesUnreasonableResultRects) {
// When the scale ratio is too great for even a 1x1 rect to be scaled:
EXPECT_EQ(gfx::Rect(),
ComputeResultRect(gfx::Rect(1, 1, 1, 1), gfx::Vector2d(1, 1),
gfx::Vector2d(1 << 30, 1)));
EXPECT_EQ(gfx::Rect(),
ComputeResultRect(gfx::Rect(1, 1, 1, 1), gfx::Vector2d(1, 1),
gfx::Vector2d(1, 1 << 30)));
EXPECT_EQ(gfx::Rect(),
ComputeResultRect(gfx::Rect(1, 1, 1, 1), gfx::Vector2d(1, 1),
gfx::Vector2d(1 << 30, 1 << 30)));
// When the rect and scale ratio are large, but produce unreasonable results:
EXPECT_EQ(gfx::Rect(), ComputeResultRect(gfx::Rect(0, 0, 1 << 12, 1 << 13),
gfx::Vector2d(1, 1),
gfx::Vector2d(1 << 4, 1 << 3)));
EXPECT_EQ(gfx::Rect(), ComputeResultRect(gfx::Rect(1 << 20, 1 << 21, 1, 1),
gfx::Vector2d(1, 1),
gfx::Vector2d(1 << 4, 1 << 3)));
EXPECT_EQ(
gfx::Rect(),
ComputeResultRect(gfx::Rect(-(1 << 20), -(1 << 21), 1, 1),
gfx::Vector2d(1, 1), gfx::Vector2d(1 << 4, 1 << 3)));
// Boundary condition: Right on the edge of "unreasonable."
EXPECT_EQ(gfx::Rect((1 << 9) * ((1 << 15) - 1), 1, (1 << 15) - 1, 1),
ComputeResultRect(gfx::Rect(1 << 9, 1, 1, 1), gfx::Vector2d(1, 1),
gfx::Vector2d((1 << 15) - 1, 1)));
EXPECT_EQ(
gfx::Rect(-(1 << 9) * ((1 << 15) - 1), 1, (1 << 15) - 1, 1),
ComputeResultRect(gfx::Rect(-(1 << 9), 1, 1, 1), gfx::Vector2d(1, 1),
gfx::Vector2d((1 << 15) - 1, 1)));
EXPECT_EQ(gfx::Rect(1, (1 << 9) * ((1 << 15) - 1), 1, (1 << 15) - 1),
ComputeResultRect(gfx::Rect(1, 1 << 9, 1, 1), gfx::Vector2d(1, 1),
gfx::Vector2d(1, (1 << 15) - 1)));
EXPECT_EQ(
gfx::Rect(1, -(1 << 9) * ((1 << 15) - 1), 1, (1 << 15) - 1),
ComputeResultRect(gfx::Rect(1, -(1 << 9), 1, 1), gfx::Vector2d(1, 1),
gfx::Vector2d(1, (1 << 15) - 1)));
}
} // namespace
} // namespace copy_output
} // namespace viz