[FXCRT] Add unit tests for CFX_FloatRect::GetOuterRect()

There were none before, now there can be some.  This exposes an issue at
the edges of the integer range, where a float larger than the maximum
value of a signed 32 bit integer returns a value of the maximum negative
integer.

Unexpected behavior uncovered during debugging of Windows print imaging
issue.

Bug: chromium:1019026
Change-Id: I076f283144b0853adefec6d13ce365d6bde19a82
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/62130
Commit-Queue: Alan Screen <awscreen@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxcrt/fx_coordinates_unittest.cpp b/core/fxcrt/fx_coordinates_unittest.cpp
index 14180d7..96cf310 100644
--- a/core/fxcrt/fx_coordinates_unittest.cpp
+++ b/core/fxcrt/fx_coordinates_unittest.cpp
@@ -4,6 +4,7 @@
 
 #include "core/fxcrt/fx_coordinates.h"
 
+#include <limits>
 #include <vector>
 
 #include "testing/gtest/include/gtest/gtest.h"
@@ -73,6 +74,65 @@
   EXPECT_FLOAT_EQ(6.3f, rect.top);
 }
 
+TEST(CFX_FloatRect, GetOuterRect) {
+  FX_RECT outer_rect;
+  CFX_FloatRect rect;
+  constexpr float kMinFloat = std::numeric_limits<float>::min();
+  constexpr int kMaxInt = std::numeric_limits<int>::max();
+  constexpr int kMinInt = std::numeric_limits<int>::min();
+  constexpr float kMinIntAsFloat = static_cast<float>(kMinInt);
+  constexpr float kMaxIntAsFloat = static_cast<float>(kMaxInt);
+
+  outer_rect = rect.GetOuterRect();
+  EXPECT_EQ(0, rect.left);
+  EXPECT_EQ(0, rect.bottom);
+  EXPECT_EQ(0, rect.right);
+  EXPECT_EQ(0, rect.top);
+
+  // Function converts from float to int using floor() for left and top, and
+  // ceil() for right and bottom.
+  rect = CFX_FloatRect(-1.1f, 3.6f, 4.4f, -5.7f);
+  outer_rect = rect.GetOuterRect();
+  EXPECT_EQ(-2, outer_rect.left);
+  EXPECT_EQ(3, outer_rect.bottom);
+  EXPECT_EQ(5, outer_rect.right);
+  EXPECT_EQ(-5, outer_rect.top);
+
+  rect = CFX_FloatRect(kMinFloat, kMinFloat, kMinFloat, kMinFloat);
+  outer_rect = rect.GetOuterRect();
+  EXPECT_EQ(0, outer_rect.left);
+  EXPECT_EQ(1, outer_rect.bottom);
+  EXPECT_EQ(1, outer_rect.right);
+  EXPECT_EQ(0, outer_rect.top);
+
+  rect = CFX_FloatRect(-kMinFloat, -kMinFloat, -kMinFloat, -kMinFloat);
+  outer_rect = rect.GetOuterRect();
+  EXPECT_EQ(-1, outer_rect.left);
+  EXPECT_EQ(0, outer_rect.bottom);
+  EXPECT_EQ(0, outer_rect.right);
+  EXPECT_EQ(-1, outer_rect.top);
+
+  // Check at limits of integer range. When saturated would expect to get values
+  // that are clamped to the limits of integers, but instead it is returning all
+  // negative values that represent a rectangle as a dot in a far reach of the
+  // negative coordinate space.  crbug.com/1019026
+  rect = CFX_FloatRect(kMinIntAsFloat, kMinIntAsFloat, kMaxIntAsFloat,
+                       kMaxIntAsFloat);
+  outer_rect = rect.GetOuterRect();
+  EXPECT_EQ(kMinInt, outer_rect.left);
+  EXPECT_EQ(kMinInt, outer_rect.bottom);  // should be |kMaxInt|
+  EXPECT_EQ(kMinInt, outer_rect.right);   // should be |kMaxInt|
+  EXPECT_EQ(kMinInt, outer_rect.top);
+
+  rect = CFX_FloatRect(kMinIntAsFloat - 1.0f, kMinIntAsFloat - 1.0f,
+                       kMaxIntAsFloat + 1.0f, kMaxIntAsFloat + 1.0f);
+  outer_rect = rect.GetOuterRect();
+  EXPECT_EQ(kMinInt, outer_rect.left);
+  EXPECT_EQ(kMinInt, outer_rect.bottom);  // should be |kMaxInt|
+  EXPECT_EQ(kMinInt, outer_rect.right);   // should be |kMaxInt|
+  EXPECT_EQ(kMinInt, outer_rect.top);
+}
+
 TEST(CFX_FloatRect, Normalize) {
   CFX_FloatRect rect;
   rect.Normalize();