
Sometimes the Ink strokes applied to a PDF page can be slightly shifted in position compared to when the stroke was in the process of being drawn by the user. This is particularly noticeable for PDF pages whose size in points has a non-zero fractional component. To ensure consistent positioning between in-progress and applied strokes, update the GetInkRenderTransform() logic to match the approach that PDFium's CPDF_Page::GetDisplayMatrix() uses when drawing PDF pages. This includes omitting some instances of doing minus one for 90, 180, and 270 degree rotations. Bug: 380038343, 399133248 Change-Id: Ie9b8ca573420d558b5e17f0c67e732743f37455f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6311352 Reviewed-by: Lei Zhang <thestig@chromium.org> Commit-Queue: Alan Screen <awscreen@chromium.org> Cr-Commit-Position: refs/heads/main@{#1426629}
677 lines
29 KiB
C++
677 lines
29 KiB
C++
// Copyright 2024 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "pdf/pdf_ink_transform.h"
|
|
|
|
#include <array>
|
|
|
|
#include "pdf/page_orientation.h"
|
|
#include "pdf/pdf_ink_conversions.h"
|
|
#include "pdf/test/pdf_ink_test_helpers.h"
|
|
#include "printing/units.h"
|
|
#include "testing/gmock/include/gmock/gmock.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
#include "third_party/ink/src/ink/geometry/affine_transform.h"
|
|
#include "third_party/ink/src/ink/geometry/envelope.h"
|
|
#include "ui/gfx/geometry/axis_transform2d.h"
|
|
#include "ui/gfx/geometry/point_f.h"
|
|
#include "ui/gfx/geometry/rect.h"
|
|
#include "ui/gfx/geometry/size.h"
|
|
#include "ui/gfx/geometry/vector2d_f.h"
|
|
|
|
using printing::kUnitConversionFactorPixelsToPoints;
|
|
|
|
namespace chrome_pdf {
|
|
|
|
namespace {
|
|
|
|
// Standard page size in pixels for tests.
|
|
constexpr gfx::Size kPageSizePortrait(50, 60);
|
|
constexpr gfx::Size kPageSizePortrait2x(kPageSizePortrait.width() * 2,
|
|
kPageSizePortrait.height() * 2);
|
|
constexpr gfx::Size kPageSizeLandscape(kPageSizePortrait.height(),
|
|
kPageSizePortrait.width());
|
|
constexpr gfx::Size kPageSizeLandscape2x(kPageSizeLandscape.width() * 2,
|
|
kPageSizeLandscape.height() * 2);
|
|
|
|
// Standard page size in points for tests, corresponding to page size in pixels
|
|
// above.
|
|
constexpr gfx::SizeF kPageSizePortraitInPoints(
|
|
kPageSizePortrait.width() * kUnitConversionFactorPixelsToPoints,
|
|
kPageSizePortrait.height() * kUnitConversionFactorPixelsToPoints);
|
|
|
|
// A page size in points `kPageSizePortraitFractionalInPoints` has fractional
|
|
// component, which gets truncated when converted to integer pixels.
|
|
constexpr gfx::SizeF kPageSizePortraitFractionalInPoints(199.9f, 201.1f);
|
|
constexpr gfx::Size kPageSizePortraitFractional(266, 268);
|
|
constexpr gfx::Size kPageSizeLandscapeFractional(268, 266);
|
|
|
|
// Scale factors used in tests.
|
|
constexpr float kScaleFactor1x = 1.0f;
|
|
constexpr float kScaleFactor2x = 2.0f;
|
|
|
|
// Non-identity page scroll used in tests.
|
|
constexpr gfx::Point kPageScrollOffset(15, 25);
|
|
|
|
// Standard page content area for tests.
|
|
constexpr gfx::Rect kPageContentAreaPortraitNoOffset(gfx::Point(),
|
|
kPageSizePortrait);
|
|
constexpr gfx::Rect kPageContentAreaPortraitNoOffset2x(gfx::Point(),
|
|
kPageSizePortrait2x);
|
|
constexpr gfx::Rect kPageContentAreaLandscapeNoOffset(gfx::Point(),
|
|
kPageSizeLandscape);
|
|
|
|
// Viewport origin offset used in tests.
|
|
constexpr gfx::Vector2dF kViewportOriginOffsetNone;
|
|
|
|
// Sample input positions in screen-based coordinates, based upon the standard
|
|
// page size.
|
|
constexpr gfx::PointF kInputPositionTopLeft;
|
|
constexpr gfx::PointF kInputPositionPortraitBottomRight(49.0f, 59.0f);
|
|
constexpr gfx::PointF kInputPositionLandscapeBottomRight(59.0f, 49.0f);
|
|
constexpr gfx::PointF kInputPositionPortraitBottomRight2x(99.0f, 119.0f);
|
|
constexpr gfx::PointF kInputPositionLandscapeBottomRight2x(119.0f, 99.0f);
|
|
constexpr gfx::PointF kInputPositionInterior(40.0f, 16.0f);
|
|
constexpr gfx::PointF kInputPositionInterior2x(80.0f, 32.0f);
|
|
|
|
// Sample canonical output positions.
|
|
constexpr gfx::PointF kCanonicalPositionTopLeft;
|
|
constexpr gfx::PointF kCanonicalPositionTopRight(49.0f, 0.0f);
|
|
constexpr gfx::PointF kCanonicalPositionBottomLeft(0.0f, 59.0f);
|
|
constexpr gfx::PointF kCanonicalPositionBottomRight(49.0f, 59.0f);
|
|
|
|
// Canonical positions can have fractional parts if the scale factor was
|
|
// not 1.0. When converting from a scale of 2x, the canonical position can end
|
|
// up with an additional half.
|
|
constexpr gfx::Vector2dF kCanonicalPositionHalf(0.5f, 0.5f);
|
|
constexpr gfx::Vector2dF kCanonicalPositionHalfX(0.5f, 0.0f);
|
|
constexpr gfx::Vector2dF kCanonicalPositionHalfY(0.0f, 0.5f);
|
|
|
|
struct InputOutputPair {
|
|
gfx::PointF input_event_position;
|
|
gfx::PointF output_css_pixel;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
TEST(PdfInkTransformTest, EventPositionToCanonicalPositionIdentity) {
|
|
constexpr auto kInputsAndOutputs = std::to_array<InputOutputPair>({
|
|
InputOutputPair{kInputPositionTopLeft, kCanonicalPositionTopLeft},
|
|
InputOutputPair{kInputPositionPortraitBottomRight,
|
|
kCanonicalPositionBottomRight},
|
|
InputOutputPair{kInputPositionInterior, gfx::PointF(40.0f, 16.0f)},
|
|
});
|
|
|
|
for (const auto& input_output : kInputsAndOutputs) {
|
|
EXPECT_EQ(input_output.output_css_pixel,
|
|
EventPositionToCanonicalPosition(
|
|
input_output.input_event_position, PageOrientation::kOriginal,
|
|
kPageContentAreaPortraitNoOffset, kScaleFactor1x));
|
|
}
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, EventPositionToCanonicalPositionZoom) {
|
|
constexpr auto kInputsAndOutputs = std::to_array<InputOutputPair>({
|
|
InputOutputPair{kInputPositionTopLeft, kCanonicalPositionTopLeft},
|
|
InputOutputPair{kInputPositionPortraitBottomRight2x,
|
|
kCanonicalPositionBottomRight + kCanonicalPositionHalf},
|
|
InputOutputPair{kInputPositionInterior2x, gfx::PointF(40.0f, 16.0f)},
|
|
});
|
|
|
|
for (const auto& input_output : kInputsAndOutputs) {
|
|
EXPECT_EQ(input_output.output_css_pixel,
|
|
EventPositionToCanonicalPosition(
|
|
input_output.input_event_position, PageOrientation::kOriginal,
|
|
kPageContentAreaPortraitNoOffset2x, kScaleFactor2x));
|
|
}
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, EventPositionToCanonicalPositionRotateClockwise90) {
|
|
constexpr auto kInputsAndOutputs = std::to_array<InputOutputPair>({
|
|
InputOutputPair{kInputPositionTopLeft, kCanonicalPositionBottomLeft},
|
|
InputOutputPair{kInputPositionLandscapeBottomRight,
|
|
kCanonicalPositionTopRight},
|
|
InputOutputPair{kInputPositionInterior, gfx::PointF(16.0f, 19.0f)},
|
|
});
|
|
|
|
for (const auto& input_output : kInputsAndOutputs) {
|
|
EXPECT_EQ(
|
|
input_output.output_css_pixel,
|
|
EventPositionToCanonicalPosition(
|
|
input_output.input_event_position, PageOrientation::kClockwise90,
|
|
kPageContentAreaLandscapeNoOffset, kScaleFactor1x));
|
|
}
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, EventPositionToCanonicalPositionRotateClockwise180) {
|
|
constexpr auto kInputsAndOutputs = std::to_array<InputOutputPair>({
|
|
InputOutputPair{kInputPositionTopLeft, kCanonicalPositionBottomRight},
|
|
InputOutputPair{kInputPositionPortraitBottomRight,
|
|
kCanonicalPositionTopLeft},
|
|
InputOutputPair{kInputPositionInterior, gfx::PointF(9.0f, 43.0f)},
|
|
});
|
|
|
|
for (const auto& input_output : kInputsAndOutputs) {
|
|
EXPECT_EQ(
|
|
input_output.output_css_pixel,
|
|
EventPositionToCanonicalPosition(
|
|
input_output.input_event_position, PageOrientation::kClockwise180,
|
|
kPageContentAreaPortraitNoOffset, kScaleFactor1x));
|
|
}
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, EventPositionToCanonicalPositionRotateClockwise270) {
|
|
constexpr auto kInputsAndOutputs = std::to_array<InputOutputPair>({
|
|
InputOutputPair{kInputPositionTopLeft, kCanonicalPositionTopRight},
|
|
InputOutputPair{kInputPositionLandscapeBottomRight,
|
|
kCanonicalPositionBottomLeft},
|
|
InputOutputPair{kInputPositionInterior, gfx::PointF(33.0f, 40.0f)},
|
|
});
|
|
|
|
for (const auto& input_output : kInputsAndOutputs) {
|
|
EXPECT_EQ(
|
|
input_output.output_css_pixel,
|
|
EventPositionToCanonicalPosition(
|
|
input_output.input_event_position, PageOrientation::kClockwise270,
|
|
kPageContentAreaLandscapeNoOffset, kScaleFactor1x));
|
|
}
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, EventPositionToCanonicalPositionScrolled) {
|
|
constexpr gfx::Point kPageContentRectOrigin(-8, -14);
|
|
const auto kInputsAndOutputs = std::to_array<InputOutputPair>({
|
|
InputOutputPair{
|
|
kInputPositionTopLeft + kPageContentRectOrigin.OffsetFromOrigin(),
|
|
kCanonicalPositionTopLeft},
|
|
InputOutputPair{kInputPositionPortraitBottomRight +
|
|
kPageContentRectOrigin.OffsetFromOrigin(),
|
|
kCanonicalPositionBottomRight},
|
|
InputOutputPair{kInputPositionInterior, gfx::PointF(48.0f, 30.0f)},
|
|
});
|
|
|
|
for (const auto& input_output : kInputsAndOutputs) {
|
|
EXPECT_EQ(input_output.output_css_pixel,
|
|
EventPositionToCanonicalPosition(
|
|
input_output.input_event_position, PageOrientation::kOriginal,
|
|
/*page_content_rect=*/
|
|
gfx::Rect(kPageContentRectOrigin, kPageSizePortrait),
|
|
kScaleFactor1x));
|
|
}
|
|
}
|
|
|
|
TEST(PdfInkTransformTest,
|
|
EventPositionToCanonicalPositionZoomScrolledClockwise90) {
|
|
constexpr gfx::Point kPageContentRectOrigin(-16, -28);
|
|
const auto kInputsAndOutputs = std::to_array<InputOutputPair>({
|
|
InputOutputPair{
|
|
kInputPositionTopLeft + kPageContentRectOrigin.OffsetFromOrigin(),
|
|
kCanonicalPositionBottomLeft + kCanonicalPositionHalfY},
|
|
InputOutputPair{kInputPositionLandscapeBottomRight2x +
|
|
kPageContentRectOrigin.OffsetFromOrigin(),
|
|
kCanonicalPositionTopRight + kCanonicalPositionHalfX},
|
|
InputOutputPair{kInputPositionInterior2x, gfx::PointF(30.0f, 11.5f)},
|
|
});
|
|
|
|
for (const auto& input_output : kInputsAndOutputs) {
|
|
EXPECT_EQ(
|
|
input_output.output_css_pixel,
|
|
EventPositionToCanonicalPosition(
|
|
input_output.input_event_position, PageOrientation::kClockwise90,
|
|
/*page_content_rect=*/
|
|
gfx::Rect(kPageContentRectOrigin, kPageSizeLandscape2x),
|
|
kScaleFactor2x));
|
|
}
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, RenderTransformIdentity) {
|
|
ink::AffineTransform transform = GetInkRenderTransform(
|
|
kViewportOriginOffsetNone, PageOrientation::kOriginal,
|
|
kPageContentAreaPortraitNoOffset, kPageSizePortraitInPoints);
|
|
EXPECT_THAT(transform,
|
|
InkAffineTransformEq(1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f));
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, RenderTransformZoom) {
|
|
ink::AffineTransform transform = GetInkRenderTransform(
|
|
kViewportOriginOffsetNone, PageOrientation::kOriginal,
|
|
kPageContentAreaPortraitNoOffset2x, kPageSizePortraitInPoints);
|
|
EXPECT_THAT(transform,
|
|
InkAffineTransformEq(2.0f, 0.0f, 0.0f, 0.0f, 2.0f, 0.0f));
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, RenderTransformRotateClockwise90) {
|
|
ink::AffineTransform transform = GetInkRenderTransform(
|
|
kViewportOriginOffsetNone, PageOrientation::kClockwise90,
|
|
kPageContentAreaLandscapeNoOffset, kPageSizePortraitInPoints);
|
|
EXPECT_THAT(transform,
|
|
InkAffineTransformEq(0.0f, -1.0f, 60.0f, 1.0f, 0.0f, 0.0f));
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, RenderTransformRotateClockwise180) {
|
|
ink::AffineTransform transform = GetInkRenderTransform(
|
|
kViewportOriginOffsetNone, PageOrientation::kClockwise180,
|
|
kPageContentAreaPortraitNoOffset, kPageSizePortraitInPoints);
|
|
EXPECT_THAT(transform,
|
|
InkAffineTransformEq(-1.0f, 0.0f, 50.0f, 0.0f, -1.0f, 60.0f));
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, RenderTransformRotateClockwise270) {
|
|
ink::AffineTransform transform = GetInkRenderTransform(
|
|
kViewportOriginOffsetNone, PageOrientation::kClockwise270,
|
|
kPageContentAreaLandscapeNoOffset, kPageSizePortraitInPoints);
|
|
EXPECT_THAT(transform,
|
|
InkAffineTransformEq(0.0f, 1.0, 0.0f, -1.0f, 0.0f, 50.0f));
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, RenderTransformScrolled) {
|
|
ink::AffineTransform transform = GetInkRenderTransform(
|
|
kViewportOriginOffsetNone, PageOrientation::kOriginal,
|
|
/*page_content_rect=*/gfx::Rect(gfx::Point(-8, -14), kPageSizePortrait),
|
|
kPageSizePortraitInPoints);
|
|
EXPECT_THAT(transform,
|
|
InkAffineTransformEq(1.0f, 0.0f, -8.0f, 0.0f, 1.0f, -14.0f));
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, RenderTransformOffsetScrolled) {
|
|
ink::AffineTransform transform = GetInkRenderTransform(
|
|
/*viewport_origin_offset=*/gfx::Vector2dF(18.0f, 24.0f),
|
|
PageOrientation::kOriginal,
|
|
/*page_content_rect=*/gfx::Rect(gfx::Point(0, -14), kPageSizePortrait),
|
|
kPageSizePortraitInPoints);
|
|
EXPECT_THAT(transform,
|
|
InkAffineTransformEq(1.0f, 0.0f, 18.0f, 0.0f, 1.0f, 10.0f));
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, RenderTransformZoomScrolledClockwise90) {
|
|
ink::AffineTransform transform = GetInkRenderTransform(
|
|
kViewportOriginOffsetNone, PageOrientation::kClockwise90,
|
|
/*page_content_rect=*/
|
|
gfx::Rect(gfx::Point(-16, -28), kPageSizeLandscape2x),
|
|
kPageSizePortraitInPoints);
|
|
EXPECT_THAT(transform,
|
|
InkAffineTransformEq(0.0f, -2.0, 104.0f, 2.0f, 0.0f, -28.0f));
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, RenderTransformOffsetZoomScrolledClockwise90) {
|
|
ink::AffineTransform transform = GetInkRenderTransform(
|
|
/*viewport_origin_offset=*/gfx::Vector2dF(18.0f, 24.0f),
|
|
PageOrientation::kClockwise90,
|
|
/*page_content_rect=*/gfx::Rect(gfx::Point(0, -28), kPageSizeLandscape2x),
|
|
kPageSizePortraitInPoints);
|
|
EXPECT_THAT(transform,
|
|
InkAffineTransformEq(0.0f, -2.0, 138.0f, 2.0f, 0.0f, -4.0f));
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, RenderTransformFractionalPointsSizeIdentity) {
|
|
ink::AffineTransform transform = GetInkRenderTransform(
|
|
kViewportOriginOffsetNone, PageOrientation::kOriginal,
|
|
gfx::Rect(gfx::Point(), kPageSizePortraitFractional),
|
|
kPageSizePortraitFractionalInPoints);
|
|
EXPECT_THAT(transform, InkAffineTransformEq(0.997999012f, 0.0f, 0.0f, 0.0f,
|
|
0.999502718f, 0.0f));
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, RenderTransformFractionalPointsSizeClockwise90) {
|
|
ink::AffineTransform transform = GetInkRenderTransform(
|
|
kViewportOriginOffsetNone, PageOrientation::kClockwise90,
|
|
gfx::Rect(gfx::Point(), kPageSizeLandscapeFractional),
|
|
kPageSizePortraitFractionalInPoints);
|
|
EXPECT_THAT(transform, InkAffineTransformEq(0.0f, -0.997999012f, 268.0f,
|
|
0.999502718f, 0.0f, 0.0f));
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, RenderTransformFractionalPointsSizeClockwise180) {
|
|
ink::AffineTransform transform = GetInkRenderTransform(
|
|
kViewportOriginOffsetNone, PageOrientation::kClockwise180,
|
|
gfx::Rect(gfx::Point(), kPageSizePortraitFractional),
|
|
kPageSizePortraitFractionalInPoints);
|
|
EXPECT_THAT(transform, InkAffineTransformEq(-0.997999012f, 0.0f, 266.0f, 0.0f,
|
|
-0.999502718f, 268.0f));
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, RenderTransformFractionalPointsSizeClockwise270) {
|
|
ink::AffineTransform transform = GetInkRenderTransform(
|
|
kViewportOriginOffsetNone, PageOrientation::kClockwise270,
|
|
gfx::Rect(gfx::Point(), kPageSizeLandscapeFractional),
|
|
kPageSizePortraitFractionalInPoints);
|
|
EXPECT_THAT(transform, InkAffineTransformEq(0.0f, 0.997999012f, 0.0f,
|
|
-0.999502718f, 0.0f, 266.0f));
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, ThumbnailTransformNoZoom) {
|
|
{
|
|
ink::AffineTransform transform = GetInkThumbnailTransform(
|
|
/*canvas_size=*/{50, 60}, PageOrientation::kOriginal,
|
|
kPageContentAreaPortraitNoOffset, kScaleFactor1x);
|
|
EXPECT_THAT(transform,
|
|
InkAffineTransformEq(1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f));
|
|
}
|
|
{
|
|
ink::AffineTransform transform = GetInkThumbnailTransform(
|
|
/*canvas_size=*/{120, 100}, PageOrientation::kOriginal,
|
|
kPageContentAreaPortraitNoOffset, kScaleFactor1x);
|
|
EXPECT_THAT(transform, InkAffineTransformEq(1.6666666f, 0.0f, 0.0f, 0.0f,
|
|
1.6666666f, 0.0f));
|
|
}
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, ThumbnailTransformZoom) {
|
|
{
|
|
ink::AffineTransform transform = GetInkThumbnailTransform(
|
|
/*canvas_size=*/{50, 60}, PageOrientation::kOriginal,
|
|
kPageContentAreaPortraitNoOffset, kScaleFactor2x);
|
|
EXPECT_THAT(transform,
|
|
InkAffineTransformEq(2.0f, 0.0f, 0.0f, 0.0f, 2.0f, 0.0f));
|
|
}
|
|
{
|
|
ink::AffineTransform transform = GetInkThumbnailTransform(
|
|
/*canvas_size=*/{120, 100}, PageOrientation::kOriginal,
|
|
kPageContentAreaPortraitNoOffset, kScaleFactor2x);
|
|
EXPECT_THAT(transform, InkAffineTransformEq(3.333333f, 0.0f, 0.0f, 0.0f,
|
|
3.333333f, 0.0f));
|
|
}
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, ThumbnailTransformRotate) {
|
|
{
|
|
ink::AffineTransform transform = GetInkThumbnailTransform(
|
|
/*canvas_size=*/{50, 60}, PageOrientation::kClockwise90,
|
|
kPageContentAreaPortraitNoOffset, kScaleFactor1x);
|
|
EXPECT_THAT(transform, InkAffineTransformEq(0.8333333f, 0.0f, 0.0f, 0.0f,
|
|
0.8333333f, 0.0f));
|
|
}
|
|
{
|
|
ink::AffineTransform transform = GetInkThumbnailTransform(
|
|
/*canvas_size=*/{120, 100}, PageOrientation::kClockwise90,
|
|
kPageContentAreaPortraitNoOffset, kScaleFactor1x);
|
|
EXPECT_THAT(transform,
|
|
InkAffineTransformEq(2.0f, 0.0f, 0.0f, 0.0f, 2.0f, 0.0f));
|
|
}
|
|
{
|
|
ink::AffineTransform transform = GetInkThumbnailTransform(
|
|
/*canvas_size=*/{50, 60}, PageOrientation::kClockwise180,
|
|
kPageContentAreaPortraitNoOffset, kScaleFactor1x);
|
|
EXPECT_THAT(transform,
|
|
InkAffineTransformEq(1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f));
|
|
}
|
|
{
|
|
ink::AffineTransform transform = GetInkThumbnailTransform(
|
|
/*canvas_size=*/{120, 100}, PageOrientation::kClockwise180,
|
|
kPageContentAreaPortraitNoOffset, kScaleFactor1x);
|
|
EXPECT_THAT(transform, InkAffineTransformEq(1.6666666f, 0.0f, 0.0f, 0.0f,
|
|
1.6666666f, 0.0f));
|
|
}
|
|
{
|
|
ink::AffineTransform transform = GetInkThumbnailTransform(
|
|
/*canvas_size=*/{50, 60}, PageOrientation::kClockwise270,
|
|
kPageContentAreaPortraitNoOffset, kScaleFactor1x);
|
|
EXPECT_THAT(transform, InkAffineTransformEq(0.8333333f, 0.0f, 0.0f, 0.0f,
|
|
0.8333333f, 0.0f));
|
|
}
|
|
{
|
|
ink::AffineTransform transform = GetInkThumbnailTransform(
|
|
/*canvas_size=*/{120, 100}, PageOrientation::kClockwise270,
|
|
kPageContentAreaPortraitNoOffset, kScaleFactor1x);
|
|
EXPECT_THAT(transform,
|
|
InkAffineTransformEq(2.0f, 0.0f, 0.0f, 0.0f, 2.0f, 0.0f));
|
|
}
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, ThumbnailTransformRotateAndZoom) {
|
|
{
|
|
ink::AffineTransform transform = GetInkThumbnailTransform(
|
|
/*canvas_size=*/{50, 60}, PageOrientation::kClockwise90,
|
|
kPageContentAreaPortraitNoOffset, kScaleFactor2x);
|
|
EXPECT_THAT(transform, InkAffineTransformEq(1.6666666f, 0.0f, 0.0f, 0.0f,
|
|
1.6666666f, 0.0f));
|
|
}
|
|
{
|
|
ink::AffineTransform transform = GetInkThumbnailTransform(
|
|
/*canvas_size=*/{120, 100}, PageOrientation::kClockwise90,
|
|
kPageContentAreaPortraitNoOffset, kScaleFactor2x);
|
|
EXPECT_THAT(transform,
|
|
InkAffineTransformEq(4.0f, 0.0f, 0.0f, 0.0f, 4.0f, 0.0f));
|
|
}
|
|
{
|
|
ink::AffineTransform transform = GetInkThumbnailTransform(
|
|
/*canvas_size=*/{50, 60}, PageOrientation::kClockwise180,
|
|
kPageContentAreaPortraitNoOffset, kScaleFactor2x);
|
|
EXPECT_THAT(transform,
|
|
InkAffineTransformEq(2.0f, 0.0f, 0.0f, 0.0f, 2.0f, 0.0f));
|
|
}
|
|
{
|
|
ink::AffineTransform transform = GetInkThumbnailTransform(
|
|
/*canvas_size=*/{120, 100}, PageOrientation::kClockwise180,
|
|
kPageContentAreaPortraitNoOffset, kScaleFactor2x);
|
|
EXPECT_THAT(transform, InkAffineTransformEq(3.333333f, 0.0f, 0.0f, 0.0f,
|
|
3.333333f, 0.0f));
|
|
}
|
|
{
|
|
ink::AffineTransform transform = GetInkThumbnailTransform(
|
|
/*canvas_size=*/{50, 60}, PageOrientation::kClockwise270,
|
|
kPageContentAreaPortraitNoOffset, kScaleFactor2x);
|
|
EXPECT_THAT(transform, InkAffineTransformEq(1.6666666f, 0.0f, 0.0f, 0.0f,
|
|
1.6666666f, 0.0f));
|
|
}
|
|
{
|
|
ink::AffineTransform transform = GetInkThumbnailTransform(
|
|
/*canvas_size=*/{120, 100}, PageOrientation::kClockwise270,
|
|
kPageContentAreaPortraitNoOffset, kScaleFactor2x);
|
|
EXPECT_THAT(transform,
|
|
InkAffineTransformEq(4.0f, 0.0f, 0.0f, 0.0f, 4.0f, 0.0f));
|
|
}
|
|
}
|
|
|
|
TEST(PdfInkTransformTest,
|
|
CanonicalInkEnvelopeToInvalidationScreenRectIdentity) {
|
|
// Representation of page contents in screen coordinates without scale or
|
|
// rotation.
|
|
constexpr gfx::Rect kPageContentRect(kPageSizePortrait);
|
|
|
|
{
|
|
// Envelope that covers the entire page contents, in canonical coordinates.
|
|
ink::Envelope envelope(InkPointFromGfxPoint(kCanonicalPositionTopLeft));
|
|
envelope.Add(InkPointFromGfxPoint(kCanonicalPositionBottomRight));
|
|
|
|
// Invalidation rectangle for `envelope` should result in the same value as
|
|
// the entire page contents.
|
|
gfx::Rect screen_rect = CanonicalInkEnvelopeToInvalidationScreenRect(
|
|
envelope, PageOrientation::kOriginal, kPageContentRect, kScaleFactor1x);
|
|
EXPECT_EQ(screen_rect, kPageContentRect);
|
|
}
|
|
|
|
{
|
|
// Envelope that covers a portion of page contents, in canonical
|
|
// coordinates.
|
|
ink::Envelope envelope(InkPointFromGfxPoint({20.0f, 35.0f}));
|
|
envelope.Add(InkPointFromGfxPoint({40.0f, 45.0f}));
|
|
|
|
// Invalidation rectangle for `envelope` should result in same value as
|
|
// input.
|
|
gfx::Rect screen_rect = CanonicalInkEnvelopeToInvalidationScreenRect(
|
|
envelope, PageOrientation::kOriginal, kPageContentRect, kScaleFactor1x);
|
|
EXPECT_EQ(screen_rect, gfx::Rect(20.0f, 35.0f, 21.0f, 11.0f));
|
|
}
|
|
}
|
|
|
|
TEST(PdfInkTransformTest,
|
|
CanonicalInkEnvelopeToInvalidationScreenRectScaledAndRotated90) {
|
|
// Scaled and rotated representation of page contents in screen coordinates.
|
|
constexpr gfx::Rect kPageContentRect({0, 0}, kPageSizeLandscape2x);
|
|
|
|
{
|
|
// Envelope that covers the entire page contents, in canonical coordinates.
|
|
ink::Envelope envelope(InkPointFromGfxPoint(kCanonicalPositionTopLeft));
|
|
envelope.Add(InkPointFromGfxPoint(kCanonicalPositionBottomRight +
|
|
kCanonicalPositionHalf));
|
|
|
|
// Invalidation rectangle for `envelope` should be scaled and rotated,
|
|
// resulting in the same value as the entire page contents.
|
|
gfx::Rect screen_rect = CanonicalInkEnvelopeToInvalidationScreenRect(
|
|
envelope, PageOrientation::kClockwise90, kPageContentRect,
|
|
kScaleFactor2x);
|
|
EXPECT_EQ(screen_rect, kPageContentRect);
|
|
}
|
|
|
|
{
|
|
// Envelope that covers a portion of page contents, in canonical
|
|
// coordinates.
|
|
ink::Envelope envelope(InkPointFromGfxPoint({20.0f, 35.0f}));
|
|
envelope.Add(InkPointFromGfxPoint({40.0f, 45.0f}));
|
|
|
|
// Invalidation rectangle for `envelope` should be scaled and rotated.
|
|
gfx::Rect screen_rect = CanonicalInkEnvelopeToInvalidationScreenRect(
|
|
envelope, PageOrientation::kClockwise90, kPageContentRect,
|
|
kScaleFactor2x);
|
|
EXPECT_EQ(screen_rect, gfx::Rect(29.0f, 40.0f, 21.0f, 41.0f));
|
|
}
|
|
}
|
|
|
|
TEST(PdfInkTransformTest,
|
|
CanonicalInkEnvelopeToInvalidationScreenRectScaledAndRotated180) {
|
|
// Scaled and rotated representation of page contents in screen coordinates.
|
|
constexpr gfx::Rect kPageContentRect({0, 0}, kPageSizePortrait2x);
|
|
|
|
{
|
|
// Envelope that covers the entire page contents, in canonical coordinates.
|
|
ink::Envelope envelope(InkPointFromGfxPoint(kCanonicalPositionTopLeft));
|
|
envelope.Add(InkPointFromGfxPoint(kCanonicalPositionBottomRight +
|
|
kCanonicalPositionHalf));
|
|
|
|
// Invalidation rectangle for `envelope` should be scaled and rotated,
|
|
// resulting in the same value as the entire page contents.
|
|
gfx::Rect screen_rect = CanonicalInkEnvelopeToInvalidationScreenRect(
|
|
envelope, PageOrientation::kClockwise180, kPageContentRect,
|
|
kScaleFactor2x);
|
|
EXPECT_EQ(screen_rect, kPageContentRect);
|
|
}
|
|
|
|
{
|
|
// Envelope that covers a portion of page contents, in canonical
|
|
// coordinates.
|
|
ink::Envelope envelope(InkPointFromGfxPoint({20.0f, 35.0f}));
|
|
envelope.Add(InkPointFromGfxPoint({40.0f, 45.0f}));
|
|
|
|
// Invalidation rectangle for `envelope` should be scaled and rotated.
|
|
gfx::Rect screen_rect = CanonicalInkEnvelopeToInvalidationScreenRect(
|
|
envelope, PageOrientation::kClockwise180, kPageContentRect,
|
|
kScaleFactor2x);
|
|
EXPECT_EQ(screen_rect, gfx::Rect(19.0f, 29.0f, 41.0f, 21.0f));
|
|
}
|
|
}
|
|
|
|
TEST(PdfInkTransformTest,
|
|
CanonicalInkEnvelopeToInvalidationScreenRectScaledAndRotated270) {
|
|
// Scaled and rotated representation of page contents in screen coordinates.
|
|
constexpr gfx::Rect kPageContentRect({0, 0}, kPageSizeLandscape2x);
|
|
|
|
{
|
|
// Envelope that covers the entire page contents, in canonical coordinates.
|
|
ink::Envelope envelope(InkPointFromGfxPoint(kCanonicalPositionTopLeft));
|
|
envelope.Add(InkPointFromGfxPoint(kCanonicalPositionBottomRight +
|
|
kCanonicalPositionHalf));
|
|
|
|
// Invalidation rectangle for `envelope` should be scaled and rotated,
|
|
// resulting in the same value as the entire page contents.
|
|
gfx::Rect screen_rect = CanonicalInkEnvelopeToInvalidationScreenRect(
|
|
envelope, PageOrientation::kClockwise270, kPageContentRect,
|
|
kScaleFactor2x);
|
|
EXPECT_EQ(screen_rect, kPageContentRect);
|
|
}
|
|
|
|
{
|
|
// Envelope that covers a portion of page contents, in canonical
|
|
// coordinates.
|
|
ink::Envelope envelope(InkPointFromGfxPoint({20.0f, 35.0f}));
|
|
envelope.Add(InkPointFromGfxPoint({40.0f, 45.0f}));
|
|
|
|
// Invalidation rectangle for `envelope` should be scaled and rotated.
|
|
gfx::Rect screen_rect = CanonicalInkEnvelopeToInvalidationScreenRect(
|
|
envelope, PageOrientation::kClockwise270, kPageContentRect,
|
|
kScaleFactor2x);
|
|
EXPECT_EQ(screen_rect, gfx::Rect(70.0f, 19.0f, 21.0f, 41.0f));
|
|
}
|
|
}
|
|
|
|
TEST(PdfInkTransformTest,
|
|
CanonicalInkEnvelopeToInvalidationScreenRectScrolled) {
|
|
// Representation of page contents in screen coordinates without scale or
|
|
// rotation, but with a scroll.
|
|
constexpr gfx::Rect kPageContentRect(kPageScrollOffset, kPageSizePortrait);
|
|
|
|
{
|
|
// Envelope that covers the entire page contents, in canonical coordinates.
|
|
ink::Envelope envelope(InkPointFromGfxPoint(kCanonicalPositionTopLeft));
|
|
envelope.Add(InkPointFromGfxPoint(kCanonicalPositionBottomRight));
|
|
|
|
// Invalidation rectangle for `envelope` should result in the same value as
|
|
// the entire page contents.
|
|
gfx::Rect screen_rect = CanonicalInkEnvelopeToInvalidationScreenRect(
|
|
envelope, PageOrientation::kOriginal, kPageContentRect, kScaleFactor1x);
|
|
EXPECT_EQ(screen_rect, kPageContentRect);
|
|
}
|
|
|
|
{
|
|
// Envelope that covers a portion of page contents, in canonical
|
|
// coordinates.
|
|
ink::Envelope envelope(InkPointFromGfxPoint({20.0f, 35.0f}));
|
|
envelope.Add(InkPointFromGfxPoint({40.0f, 45.0f}));
|
|
|
|
// Invalidation rectangle for `envelope` should result in same value as
|
|
// input but shifted for the scroll amount.
|
|
gfx::Rect screen_rect = CanonicalInkEnvelopeToInvalidationScreenRect(
|
|
envelope, PageOrientation::kOriginal, kPageContentRect, kScaleFactor1x);
|
|
EXPECT_EQ(screen_rect, gfx::Rect(35.0f, 60.0f, 21.0f, 11.0f));
|
|
}
|
|
}
|
|
|
|
TEST(PdfInkTransformTest,
|
|
CanonicalInkEnvelopeToInvalidationScreenRectScrolledScaledAndRotated) {
|
|
// Scaled and rotated representation of page contents in screen coordinates.
|
|
constexpr gfx::Rect kPageContentRect(kPageScrollOffset, kPageSizeLandscape2x);
|
|
|
|
{
|
|
// Envelope that covers the entire page contents, in canonical coordinates.
|
|
ink::Envelope envelope(InkPointFromGfxPoint(kCanonicalPositionTopLeft));
|
|
envelope.Add(InkPointFromGfxPoint(kCanonicalPositionBottomRight +
|
|
kCanonicalPositionHalf));
|
|
|
|
// Invalidation rectangle for `envelope` should be scaled and rotated,
|
|
// resulting in the same value as the entire page contents.
|
|
gfx::Rect screen_rect = CanonicalInkEnvelopeToInvalidationScreenRect(
|
|
envelope, PageOrientation::kClockwise90, kPageContentRect,
|
|
kScaleFactor2x);
|
|
EXPECT_EQ(screen_rect, kPageContentRect);
|
|
}
|
|
|
|
{
|
|
// Envelope that covers a portion of page contents, in canonical
|
|
// coordinates.
|
|
ink::Envelope envelope(InkPointFromGfxPoint({20.0f, 35.0f}));
|
|
envelope.Add(InkPointFromGfxPoint({40.0f, 45.0f}));
|
|
|
|
// Invalidation rectangle for `envelope` should be scaled and rotated, and
|
|
// shifted for the scroll amount.
|
|
gfx::Rect screen_rect = CanonicalInkEnvelopeToInvalidationScreenRect(
|
|
envelope, PageOrientation::kClockwise90, kPageContentRect,
|
|
kScaleFactor2x);
|
|
EXPECT_EQ(screen_rect, gfx::Rect(44.0f, 65.0f, 21.0f, 41.0f));
|
|
}
|
|
}
|
|
|
|
TEST(PdfInkTransformTest, GetCanonicalToPdfTransform) {
|
|
{
|
|
gfx::AxisTransform2d tr = GetCanonicalToPdfTransform(/*page_height=*/0);
|
|
EXPECT_EQ(gfx::Vector2dF(0.75f, -0.75f), tr.scale());
|
|
EXPECT_EQ(gfx::Vector2dF(0, 0), tr.translation());
|
|
}
|
|
{
|
|
gfx::AxisTransform2d tr = GetCanonicalToPdfTransform(/*page_height=*/712);
|
|
EXPECT_EQ(gfx::Vector2dF(0.75f, -0.75f), tr.scale());
|
|
EXPECT_EQ(gfx::Vector2dF(0, 712), tr.translation());
|
|
}
|
|
}
|
|
|
|
} // namespace chrome_pdf
|