Add unit tests for PostScript EMF DC clip box clamping

Add CFXRenderDeviceTest.WindowsEmfPostScriptClipBox and
CFXRenderDeviceTest.WindowsEmfPostScriptClipRgn to demonstrate
CFX_PSRenderer::SetClip_PathFill() currently behaves strangely and
calculate negative clip box heights. Add TODO comments to fix that.

TAG=agy
CONV=6b3124d0-7f12-417c-b771-b63010dc7351

Bug: 553140224
Change-Id: Iafd05a9b4af9402bc58059336928bc764e1d19c0
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/157750
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxge/cfx_renderdevice_unittest.cpp b/core/fxge/cfx_renderdevice_unittest.cpp
index 41020b2..7103b8f 100644
--- a/core/fxge/cfx_renderdevice_unittest.cpp
+++ b/core/fxge/cfx_renderdevice_unittest.cpp
@@ -17,6 +17,11 @@
 
 #if BUILDFLAG(IS_WIN)
 #include <windows.h>
+
+#include <memory>
+#include <type_traits>
+
+#include "core/fxge/cfx_gemodule.h"
 #include "core/fxge/win32/cfx_psfonttracker.h"
 #endif
 
@@ -91,6 +96,31 @@
 
 constexpr CFX_Matrix kIdentityMatrix;
 
+class ScopedPrintMode {
+ public:
+  explicit ScopedPrintMode(WindowsPrintMode mode)
+      : old_mode_(CFX_GEModule::GetPrintMode()) {
+    CFX_GEModule::SetPrintMode(mode);
+  }
+  ~ScopedPrintMode() { CFX_GEModule::SetPrintMode(old_mode_); }
+
+ private:
+  const WindowsPrintMode old_mode_;
+};
+
+struct EnhMetaFileDCDeleter {
+  void operator()(HDC dc) const { ::DeleteEnhMetaFile(::CloseEnhMetaFile(dc)); }
+};
+using ScopedEnhMetaFileDC =
+    std::unique_ptr<std::remove_pointer_t<HDC>, EnhMetaFileDCDeleter>;
+
+struct GdiObjectDeleter {
+  void operator()(HGDIOBJ object) const { ::DeleteObject(object); }
+};
+template <typename T>
+using ScopedGdiObject =
+    std::unique_ptr<std::remove_pointer_t<T>, GdiObjectDeleter>;
+
 }  // namespace
 
 class CFXWindowsRenderDeviceTest : public testing::Test {
@@ -170,4 +200,49 @@
   EXPECT_TRUE(device_->SetClip_PathFill(
       path_data, &kIdentityMatrix, CFX_FillRenderOptions::WindingOptions()));
 }
-#endif
+
+TEST(CFXRenderDeviceTest, WindowsEmfPostScriptClipBox) {
+  ScopedPrintMode scoped_print_mode(WindowsPrintMode::kPostScript2);
+  ScopedEnhMetaFileDC dc_handle(
+      ::CreateEnhMetaFile(nullptr, nullptr, nullptr, nullptr));
+  ASSERT_TRUE(dc_handle);
+
+  const int horz_res = ::GetDeviceCaps(dc_handle.get(), HORZRES);
+  const int vert_res = ::GetDeviceCaps(dc_handle.get(), VERTRES);
+  const FX_RECT large_clip_rect(0, 0, horz_res * 2, vert_res * 2);
+
+  CFX_PSFontTracker font_tracker;
+  std::unique_ptr<CFX_RenderDevice> device =
+      CFX_RenderDevice::CreateForWindowsDC(dc_handle.get(), &font_tracker);
+  ASSERT_TRUE(device);
+  EXPECT_TRUE(device->SetClip_Rect(large_clip_rect));
+
+  // TODO(crbug.com/553140224): Clip box should be `large_clip_rect`.
+  EXPECT_EQ(FX_RECT(0, 2 * vert_res, 2 * horz_res, 0), device->GetClipBox());
+}
+
+TEST(CFXRenderDeviceTest, WindowsEmfPostScriptClipRgn) {
+  ScopedPrintMode scoped_print_mode(WindowsPrintMode::kPostScript2);
+  ScopedEnhMetaFileDC dc_handle(
+      ::CreateEnhMetaFile(nullptr, nullptr, nullptr, nullptr));
+  ASSERT_TRUE(dc_handle);
+
+  const int horz_res = ::GetDeviceCaps(dc_handle.get(), HORZRES);
+  const int vert_res = ::GetDeviceCaps(dc_handle.get(), VERTRES);
+  const FX_RECT large_clip_rect(0, 0, horz_res * 2, vert_res * 2);
+
+  ScopedGdiObject<HRGN> clip_rgn(
+      ::CreateRectRgn(large_clip_rect.left, large_clip_rect.top,
+                      large_clip_rect.right, large_clip_rect.bottom));
+  ASSERT_TRUE(clip_rgn);
+  EXPECT_NE(ERROR, ::SelectClipRgn(dc_handle.get(), clip_rgn.get()));
+
+  CFX_PSFontTracker font_tracker;
+  std::unique_ptr<CFX_RenderDevice> device =
+      CFX_RenderDevice::CreateForWindowsDC(dc_handle.get(), &font_tracker);
+  ASSERT_TRUE(device);
+
+  // TODO(crbug.com/553140224): Clip box should be `large_clip_rect`.
+  EXPECT_EQ(FX_RECT(0, 2 * vert_res, 2 * horz_res, 0), device->GetClipBox());
+}
+#endif  // BUILDFLAG(IS_WIN)