提交 9b7f40ce 编写于 作者: A Alexander Alekhin

Merge pull request #21074 from vrabaud:3.4_rect

...@@ -1895,13 +1895,33 @@ Rect_<_Tp>& operator -= ( Rect_<_Tp>& a, const Size_<_Tp>& b ) ...@@ -1895,13 +1895,33 @@ Rect_<_Tp>& operator -= ( Rect_<_Tp>& a, const Size_<_Tp>& b )
template<typename _Tp> static inline template<typename _Tp> static inline
Rect_<_Tp>& operator &= ( Rect_<_Tp>& a, const Rect_<_Tp>& b ) Rect_<_Tp>& operator &= ( Rect_<_Tp>& a, const Rect_<_Tp>& b )
{ {
_Tp x1 = std::max(a.x, b.x); if (a.empty() || b.empty()) {
_Tp y1 = std::max(a.y, b.y); a = Rect();
a.width = std::min(a.x + a.width, b.x + b.width) - x1; return a;
a.height = std::min(a.y + a.height, b.y + b.height) - y1; }
a.x = x1; const Rect_<_Tp>& Rx_min = (a.x < b.x) ? a : b;
a.y = y1; const Rect_<_Tp>& Rx_max = (a.x < b.x) ? b : a;
if( a.width <= 0 || a.height <= 0 ) const Rect_<_Tp>& Ry_min = (a.y < b.y) ? a : b;
const Rect_<_Tp>& Ry_max = (a.y < b.y) ? b : a;
// Looking at the formula below, we will compute Rx_min.width - (Rx_max.x - Rx_min.x)
// but we want to avoid overflows. Rx_min.width >= 0 and (Rx_max.x - Rx_min.x) >= 0
// by definition so the difference does not overflow. The only thing that can overflow
// is (Rx_max.x - Rx_min.x). And it can only overflow if Rx_min.x < 0.
// Let us first deal with the following case.
if ((Rx_min.x < 0 && Rx_min.x + Rx_min.width < Rx_max.x) ||
(Ry_min.y < 0 && Ry_min.y + Ry_min.height < Ry_max.y)) {
a = Rect();
return a;
}
// We now know that either Rx_min.x >= 0, or
// Rx_min.x < 0 && Rx_min.x + Rx_min.width >= Rx_max.x and therefore
// Rx_min.width >= (Rx_max.x - Rx_min.x) which means (Rx_max.x - Rx_min.x)
// is inferior to a valid int and therefore does not overflow.
a.width = std::min(Rx_min.width - (Rx_max.x - Rx_min.x), Rx_max.width);
a.height = std::min(Ry_min.height - (Ry_max.y - Ry_min.y), Ry_max.height);
a.x = Rx_max.x;
a.y = Ry_max.y;
if (a.empty())
a = Rect(); a = Rect();
return a; return a;
} }
......
...@@ -784,4 +784,36 @@ TEST(Core_Check, testSize_1) ...@@ -784,4 +784,36 @@ TEST(Core_Check, testSize_1)
} }
template <typename T> class Rect_Test : public testing::Test {};
TYPED_TEST_CASE_P(Rect_Test);
// Reimplement C++11 std::numeric_limits<>::lowest.
template<typename T> T cv_numeric_limits_lowest();
template<> int cv_numeric_limits_lowest<int>() { return INT_MIN; }
template<> float cv_numeric_limits_lowest<float>() { return -FLT_MAX; }
template<> double cv_numeric_limits_lowest<double>() { return -DBL_MAX; }
TYPED_TEST_P(Rect_Test, Overflows) {
typedef Rect_<TypeParam> R;
TypeParam num_max = std::numeric_limits<TypeParam>::max();
TypeParam num_lowest = cv_numeric_limits_lowest<TypeParam>();
EXPECT_EQ(R(0, 0, 10, 10), R(0, 0, 10, 10) & R(0, 0, 10, 10));
EXPECT_EQ(R(5, 6, 4, 3), R(0, 0, 10, 10) & R(5, 6, 4, 3));
EXPECT_EQ(R(5, 6, 3, 2), R(0, 0, 8, 8) & R(5, 6, 4, 3));
// Test with overflowing dimenions.
EXPECT_EQ(R(5, 0, 5, 10), R(0, 0, 10, 10) & R(5, 0, num_max, num_max));
// Test with overflowing dimensions for floats/doubles.
EXPECT_EQ(R(num_max, 0, num_max / 4, 10), R(num_max, 0, num_max / 2, 10) & R(num_max, 0, num_max / 4, 10));
// Test with overflowing coordinates.
EXPECT_EQ(R(), R(20, 0, 10, 10) & R(num_lowest, 0, 10, 10));
EXPECT_EQ(R(), R(20, 0, 10, 10) & R(0, num_lowest, 10, 10));
EXPECT_EQ(R(), R(num_lowest, 0, 10, 10) & R(0, num_lowest, 10, 10));
}
REGISTER_TYPED_TEST_CASE_P(Rect_Test, Overflows);
typedef ::testing::Types<int, float, double> RectTypes;
INSTANTIATE_TYPED_TEST_CASE_P(Negative_Test, Rect_Test, RectTypes);
}} // namespace }} // namespace
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册