summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenrique Nakashima <hnakashima@chromium.org>2018-01-17 20:00:37 +0000
committerChromium commit bot <commit-bot@chromium.org>2018-01-17 20:00:37 +0000
commit2914b6f1303445025764ec2d9f01a3be2df5cec0 (patch)
tree6aacd2a1acbef8ef44f7eaaa5c0a5da36dff3d7b
parentc37fa7d9c5c60ac407b46bfc2e7745afa0b2df85 (diff)
downloadpdfium-2914b6f1303445025764ec2d9f01a3be2df5cec0.tar.xz
Fix behavior of FPDF_RenderPageBitmapWithMatrix
This functional part of this CL is mostly a revert of "Change behaviour of FPDF_RenderPageBitmapWithMatrix" 24b0733a72bbc4013bff8628f198b0aea807aa06 Besides the revert, the parameters passed to pPage->GetDisplayMatrix() are changed to fix a bug with the previous implementation: the page was scaled to fit inside the clipping_rect, instead of clipped. Bug: pdfium:849 Change-Id: I95d0a303a979c998026a3bd6963c8684a1209f03 Reviewed-on: https://pdfium-review.googlesource.com/22931 Reviewed-by: Nicolás Peña Moreno <npm@chromium.org> Reviewed-by: dsinclair <dsinclair@chromium.org> Commit-Queue: Henrique Nakashima <hnakashima@chromium.org>
-rw-r--r--core/fpdfapi/page/cpdf_page.cpp29
-rw-r--r--core/fpdfapi/page/cpdf_page.h6
-rw-r--r--fpdfsdk/fpdfview.cpp17
-rw-r--r--fpdfsdk/fpdfview_embeddertest.cpp266
4 files changed, 179 insertions, 139 deletions
diff --git a/core/fpdfapi/page/cpdf_page.cpp b/core/fpdfapi/page/cpdf_page.cpp
index c6f4fb2a39..ee7b5d408a 100644
--- a/core/fpdfapi/page/cpdf_page.cpp
+++ b/core/fpdfapi/page/cpdf_page.cpp
@@ -177,35 +177,6 @@ CFX_Matrix CPDF_Page::GetDisplayMatrix(int xPos,
return matrix;
}
-// This method follows the same apparent logic as GetDisplayMatrix(). For
-// example, consider point 0. First, take the top left coordinate of the
-// rectangle in the transformed space. Now, calculate what this point was in the
-// original space by inverting. Note that this is not necessarily the same as
-// the top left corner of the original rectangle.
-CFX_Matrix CPDF_Page::GetDisplayMatrixWithTransformation(
- int xPos,
- int yPos,
- int xSize,
- int ySize,
- const CFX_Matrix& transformation) {
- CFX_FloatRect rect(xPos, yPos, xPos + xSize, yPos + ySize);
- rect = transformation.TransformRect(rect);
- CFX_Matrix inverse = transformation.GetInverse();
- CFX_PointF point0(rect.left, rect.top);
- CFX_PointF point1(rect.left, rect.bottom);
- CFX_PointF point2(rect.right, rect.top);
- point0 = inverse.Transform(point0);
- point1 = inverse.Transform(point1);
- point2 = inverse.Transform(point2);
-
- CFX_Matrix matrix = m_PageMatrix;
- matrix.Concat(CFX_Matrix(
- (point2.x - point0.x) / m_PageWidth, (point2.y - point0.y) / m_PageWidth,
- (point1.x - point0.x) / m_PageHeight,
- (point1.y - point0.y) / m_PageHeight, point0.x, point0.y));
- return matrix;
-}
-
int CPDF_Page::GetPageRotation() const {
CPDF_Object* pRotate = GetPageAttr("Rotate");
int rotate = pRotate ? (pRotate->GetInteger() / 90) % 4 : 0;
diff --git a/core/fpdfapi/page/cpdf_page.h b/core/fpdfapi/page/cpdf_page.h
index e32a7f0fe8..e1b5bcfa44 100644
--- a/core/fpdfapi/page/cpdf_page.h
+++ b/core/fpdfapi/page/cpdf_page.h
@@ -38,12 +38,6 @@ class CPDF_Page : public CPDF_PageObjectHolder {
int xSize,
int ySize,
int iRotate) const;
- CFX_Matrix GetDisplayMatrixWithTransformation(
- int xPos,
- int yPos,
- int xSize,
- int ySize,
- const CFX_Matrix& transformation);
float GetPageWidth() const { return m_PageWidth; }
float GetPageHeight() const { return m_PageHeight; }
diff --git a/fpdfsdk/fpdfview.cpp b/fpdfsdk/fpdfview.cpp
index cec44a48f9..97fc02a234 100644
--- a/fpdfsdk/fpdfview.cpp
+++ b/fpdfsdk/fpdfview.cpp
@@ -1034,13 +1034,16 @@ FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap,
if (clipping)
clipping_rect = CFXFloatRectFromFSRECTF(*clipping);
FX_RECT clip_rect = clipping_rect.ToFxRect();
- RenderPageImpl(
- pContext, pPage,
- pPage->GetDisplayMatrixWithTransformation(
- clip_rect.left, clip_rect.top, clip_rect.Width(), clip_rect.Height(),
- CFX_Matrix(matrix->a, matrix->b, matrix->c, matrix->d, matrix->e,
- matrix->f)),
- clip_rect, flags, true, nullptr);
+
+ CFX_Matrix transform_matrix = pPage->GetDisplayMatrix(
+ 0, 0, pPage->GetPageWidth(), pPage->GetPageHeight(), 0);
+
+ if (matrix) {
+ transform_matrix.Concat(CFX_Matrix(matrix->a, matrix->b, matrix->c,
+ matrix->d, matrix->e, matrix->f));
+ }
+ RenderPageImpl(pContext, pPage, transform_matrix, clip_rect, flags, true,
+ nullptr);
pPage->SetRenderContext(nullptr);
}
diff --git a/fpdfsdk/fpdfview_embeddertest.cpp b/fpdfsdk/fpdfview_embeddertest.cpp
index 7e93574059..cca77c9031 100644
--- a/fpdfsdk/fpdfview_embeddertest.cpp
+++ b/fpdfsdk/fpdfview_embeddertest.cpp
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <cmath>
#include <limits>
#include <string>
-#include "core/fxcrt/fx_coordinates.h"
#include "fpdfsdk/fpdfview_c_api_test.h"
#include "public/fpdfview.h"
#include "testing/embedder_test.h"
@@ -33,7 +33,15 @@ TEST(fpdf, CApiTest) {
EXPECT_TRUE(CheckPDFiumCApi());
}
-class FPDFViewEmbeddertest : public EmbedderTest {};
+class FPDFViewEmbeddertest : public EmbedderTest {
+ protected:
+ void TestRenderPageBitmapWithMatrix(FPDF_PAGE page,
+ const int bitmap_width,
+ const int bitmap_height,
+ const FS_MATRIX& matrix,
+ const FS_RECTF& rect,
+ const char* expected_md5);
+};
TEST_F(FPDFViewEmbeddertest, Document) {
EXPECT_TRUE(OpenDocument("about_blank.pdf"));
@@ -377,113 +385,177 @@ TEST_F(FPDFViewEmbeddertest, Hang_360) {
EXPECT_FALSE(OpenDocument("bug_360.pdf"));
}
+void FPDFViewEmbeddertest::TestRenderPageBitmapWithMatrix(
+ FPDF_PAGE page,
+ const int bitmap_width,
+ const int bitmap_height,
+ const FS_MATRIX& matrix,
+ const FS_RECTF& rect,
+ const char* expected_md5) {
+ FPDF_BITMAP bitmap = FPDFBitmap_Create(bitmap_width, bitmap_height, 0);
+ FPDFBitmap_FillRect(bitmap, 0, 0, bitmap_width, bitmap_height, 0xFFFFFFFF);
+ FPDF_RenderPageBitmapWithMatrix(bitmap, page, &matrix, &rect, 0);
+ CompareBitmap(bitmap, bitmap_width, bitmap_height, expected_md5);
+ FPDFBitmap_Destroy(bitmap);
+}
+
TEST_F(FPDFViewEmbeddertest, FPDF_RenderPageBitmapWithMatrix) {
- const char* const kRotatedMD5[4] = {
- "0a90de37f52127619c3dfb642b5fa2fe", "d599429574ff0dcad3bc898ea8b874ca",
- "0113386bb0bd45125bacc6dee78bfe78", "051fcfa4c1f9de28765705633a8ef3a9"};
- const char kTopLeftQuarterMD5[] = "4982be08db3f6d2e6409186ebbced9eb";
- const char kHoriStretchedMD5[] = "004bf38f3c5c76a644e6fca204747f21";
- const char kRotateandStretchMD5[] = "0ea95cacc716d003cf063a2c5ed6c8d7";
+ const char kOriginalMD5[] = "0a90de37f52127619c3dfb642b5fa2fe";
+ const char kClippedMD5[] = "a84cab93c102b9b9290fba3047ba702c";
+ const char kTopLeftQuarterMD5[] = "f11a11137c8834389e31cf555a4a6979";
+ const char kHoriStretchedMD5[] = "48ef9205941ed19691ccfa00d717187e";
+ const char kRotated90ClockwiseMD5[] = "d8da2c7bf77521550d0f2752b9cf3482";
+ const char kRotated180ClockwiseMD5[] = "0113386bb0bd45125bacc6dee78bfe78";
+ const char kRotated270ClockwiseMD5[] = "a287e0f74ce203699cda89f9cc97a240";
+ const char kMirrorHoriMD5[] = "6e8d7a6fde39d8e720fb9e620102918c";
+ const char kMirrorVertMD5[] = "8f3a555ef9c0d5031831ae3715273707";
+ const char kLargerTopLeftQuarterMD5[] = "172a2f4adafbadbe98017b1c025b9e27";
+ const char kLargerMD5[] = "c806145641c3e6fc4e022c7065343749";
+ const char kLargerClippedMD5[] = "091d3b1c7933c8f6945eb2cb41e588e9";
+ const char kLargerRotatedMD5[] = "115f13353ebfc82ddb392d1f0059eb12";
+ const char kLargerRotatedLandscapeMD5[] = "c901239d17d84ac84cb6f2124da71b0d";
+ const char kLargerRotatedDiagonalMD5[] = "3d62417468bdaff0eb14391a0c30a3b1";
+ const char kTileMD5[] = "0a190003c97220bf8877684c8d7e89cf";
EXPECT_TRUE(OpenDocument("rectangles.pdf"));
FPDF_PAGE page = LoadPage(0);
EXPECT_NE(nullptr, page);
- const int initial_width = static_cast<int>(FPDF_GetPageWidth(page));
- const int initial_height = static_cast<int>(FPDF_GetPageHeight(page));
- EXPECT_EQ(200, initial_width);
- EXPECT_EQ(300, initial_height);
+ const int page_width = static_cast<int>(FPDF_GetPageWidth(page));
+ const int page_height = static_cast<int>(FPDF_GetPageHeight(page));
+ EXPECT_EQ(200, page_width);
+ EXPECT_EQ(300, page_height);
FPDF_BITMAP bitmap = RenderPage(page);
- CompareBitmap(bitmap, initial_width, initial_height, kRotatedMD5[0]);
+ CompareBitmap(bitmap, page_width, page_height, kOriginalMD5);
FPDFBitmap_Destroy(bitmap);
- // Try the easy rotations: 0, 90, 180, 270 clockwise. The output should be the
- // same as FPDF_RenderPageBitmap with the appropriate rotation flag. Per PDF
- // spec section 4.2.2, a t degree rotation is represented by [cos(t) sin(t)
- // -sin(t) cos(t) 0 0] (matrix goes on the right in the multiplication).
- FS_RECTF rect = {0, 0, initial_width, initial_height};
- CFX_Matrix rot_matrices[4] = {
- CFX_Matrix(1, 0, 0, 1, 0, 0), CFX_Matrix(0, -1, 1, 0, 0, 0),
- CFX_Matrix(-1, 0, 0, -1, 0, 0), CFX_Matrix(0, 1, -1, 0, 0, 0)};
- for (int rot = 0; rot < 4; ++rot) {
- int width;
- int height;
- FS_MATRIX matrix;
- matrix.a = rot_matrices[rot].a;
- matrix.b = rot_matrices[rot].b;
- matrix.c = rot_matrices[rot].c;
- matrix.d = rot_matrices[rot].d;
- matrix.e = rot_matrices[rot].e;
- matrix.f = rot_matrices[rot].f;
- if (rot % 2 == 0) {
- width = initial_width;
- height = initial_height;
- } else {
- width = initial_height;
- height = initial_width;
- }
- rect.right = width;
- rect.bottom = height;
-
- bitmap = FPDFBitmap_Create(width, height, 0);
- FPDFBitmap_FillRect(bitmap, 0, 0, width, height, 0xFFFFFFFF);
- FPDF_RenderPageBitmap(bitmap, page, 0, 0, width, height, rot, 0);
- CompareBitmap(bitmap, width, height, kRotatedMD5[rot]);
- FPDFBitmap_Destroy(bitmap);
-
- bitmap = FPDFBitmap_Create(width, height, 0);
- FPDFBitmap_FillRect(bitmap, 0, 0, width, height, 0xFFFFFFFF);
- FPDF_RenderPageBitmapWithMatrix(bitmap, page, &matrix, &rect, 0);
- CompareBitmap(bitmap, width, height, kRotatedMD5[rot]);
- FPDFBitmap_Destroy(bitmap);
- }
- // TODO(npm): what to do with transformations that do not align the page with
- // the axis, like a 45 degree rotation (currently, part of the page gets cut
- // out). pdfium:849
-
- // Now render again with the image scaled smaller.
- int width = initial_width / 2;
- int height = initial_height / 2;
- FS_MATRIX matrix = {0.5, 0, 0, 0.5, 0, 0};
-
- rect.right = width;
- rect.bottom = height;
+ FS_RECTF page_rect{0, 0, page_width, page_height};
- bitmap = FPDFBitmap_Create(width, height, 0);
- FPDFBitmap_FillRect(bitmap, 0, 0, width, height, 0xFFFFFFFF);
- FPDF_RenderPageBitmapWithMatrix(bitmap, page, &matrix, &rect, 0);
- CompareBitmap(bitmap, width, height, kTopLeftQuarterMD5);
- FPDFBitmap_Destroy(bitmap);
+ // Try rendering with an identity matrix. The output should be the same as
+ // the RenderPage() output.
+ FS_MATRIX identity_matrix{1, 0, 0, 1, 0, 0};
+ TestRenderPageBitmapWithMatrix(page, page_width, page_height, identity_matrix,
+ page_rect, kOriginalMD5);
- // Now render again with the image scaled larger horizontally.
- width = initial_width * 2;
- height = initial_height;
- matrix.a = 2;
- matrix.d = 1;
- rect.right = width;
- rect.bottom = height;
- bitmap = FPDFBitmap_Create(width, height, 0);
- FPDFBitmap_FillRect(bitmap, 0, 0, width, height, 0xFFFFFFFF);
- FPDF_RenderPageBitmapWithMatrix(bitmap, page, &matrix, &rect, 0);
- CompareBitmap(bitmap, width, height, kHoriStretchedMD5);
- FPDFBitmap_Destroy(bitmap);
+ // Again render with an identity matrix but with a smaller clipping rect.
+ FS_RECTF middle_of_page_rect{page_width / 4, page_height / 4,
+ page_width * 3 / 4, page_height * 3 / 4};
+ TestRenderPageBitmapWithMatrix(page, page_width, page_height, identity_matrix,
+ middle_of_page_rect, kClippedMD5);
- // Test a rotation followed by a stretch.
- width = initial_height * 2;
- height = initial_width;
- matrix.a = 0;
- matrix.b = -1;
- matrix.c = 2;
- matrix.d = 0;
- matrix.e = 0;
- matrix.f = 0;
- rect.right = width;
- rect.bottom = height;
- bitmap = FPDFBitmap_Create(width, height, 0);
- FPDFBitmap_FillRect(bitmap, 0, 0, width, height, 0xFFFFFFFF);
- FPDF_RenderPageBitmapWithMatrix(bitmap, page, &matrix, &rect, 0);
- CompareBitmap(bitmap, width, height, kRotateandStretchMD5);
- FPDFBitmap_Destroy(bitmap);
+ // Now render again with the image scaled smaller.
+ FS_MATRIX half_scale_matrix{0.5, 0, 0, 0.5, 0, 0};
+ TestRenderPageBitmapWithMatrix(page, page_width, page_height,
+ half_scale_matrix, page_rect,
+ kTopLeftQuarterMD5);
+
+ // Now render again with the image scaled larger horizontally (the right half
+ // will be clipped).
+ FS_MATRIX stretch_x_matrix{2, 0, 0, 1, 0, 0};
+ TestRenderPageBitmapWithMatrix(page, page_width, page_height,
+ stretch_x_matrix, page_rect,
+ kHoriStretchedMD5);
+
+ // Try a 90 degree rotation clockwise but with the same bitmap size, so part
+ // will be clipped.
+ FS_MATRIX rotate_90_matrix{0, 1, -1, 0, page_width, 0};
+ TestRenderPageBitmapWithMatrix(page, page_width, page_height,
+ rotate_90_matrix, page_rect,
+ kRotated90ClockwiseMD5);
+
+ // 180 degree rotation clockwise.
+ FS_MATRIX rotate_180_matrix{-1, 0, 0, -1, page_width, page_height};
+ TestRenderPageBitmapWithMatrix(page, page_width, page_height,
+ rotate_180_matrix, page_rect,
+ kRotated180ClockwiseMD5);
+
+ // 270 degree rotation clockwise.
+ FS_MATRIX rotate_270_matrix{0, -1, 1, 0, 0, page_width};
+ TestRenderPageBitmapWithMatrix(page, page_width, page_height,
+ rotate_270_matrix, page_rect,
+ kRotated270ClockwiseMD5);
+
+ // Mirror horizontally.
+ FS_MATRIX mirror_hori_matrix{-1, 0, 0, 1, page_width, 0};
+ TestRenderPageBitmapWithMatrix(page, page_width, page_height,
+ mirror_hori_matrix, page_rect, kMirrorHoriMD5);
+
+ // Mirror vertically.
+ FS_MATRIX mirror_vert_matrix{1, 0, 0, -1, 0, page_height};
+ TestRenderPageBitmapWithMatrix(page, page_width, page_height,
+ mirror_vert_matrix, page_rect, kMirrorVertMD5);
+
+ // Tests rendering to a larger bitmap
+ const int bitmap_width = page_width * 2;
+ const int bitmap_height = page_height * 2;
+
+ // Render using an identity matrix and the whole bitmap area as clipping rect.
+ FS_RECTF bitmap_rect{0, 0, bitmap_width, bitmap_height};
+ TestRenderPageBitmapWithMatrix(page, bitmap_width, bitmap_height,
+ identity_matrix, bitmap_rect,
+ kLargerTopLeftQuarterMD5);
+
+ // Render using a scaling matrix to fill the larger bitmap.
+ FS_MATRIX double_scale_matrix{2, 0, 0, 2, 0, 0};
+ TestRenderPageBitmapWithMatrix(page, bitmap_width, bitmap_height,
+ double_scale_matrix, bitmap_rect, kLargerMD5);
+
+ // Render the larger image again but with clipping.
+ FS_RECTF middle_of_bitmap_rect{bitmap_width / 4, bitmap_height / 4,
+ bitmap_width * 3 / 4, bitmap_height * 3 / 4};
+ TestRenderPageBitmapWithMatrix(page, bitmap_width, bitmap_height,
+ double_scale_matrix, middle_of_bitmap_rect,
+ kLargerClippedMD5);
+
+ // On the larger bitmap, try a 90 degree rotation but with the same bitmap
+ // size, so part will be clipped.
+ FS_MATRIX rotate_90_scale_2_matrix{0, 2, -2, 0, bitmap_width, 0};
+ TestRenderPageBitmapWithMatrix(page, bitmap_width, bitmap_height,
+ rotate_90_scale_2_matrix, bitmap_rect,
+ kLargerRotatedMD5);
+
+ // On the larger bitmap, apply 90 degree rotation to a bitmap with the
+ // appropriate dimensions.
+ const int landscape_bitmap_width = bitmap_height;
+ const int landscape_bitmap_height = bitmap_width;
+ FS_RECTF landscape_bitmap_rect{0, 0, landscape_bitmap_width,
+ landscape_bitmap_height};
+ FS_MATRIX landscape_rotate_90_scale_2_matrix{
+ 0, 2, -2, 0, landscape_bitmap_width, 0};
+ TestRenderPageBitmapWithMatrix(
+ page, landscape_bitmap_width, landscape_bitmap_height,
+ landscape_rotate_90_scale_2_matrix, landscape_bitmap_rect,
+ kLargerRotatedLandscapeMD5);
+
+ // On the larger bitmap, apply 45 degree rotation to a bitmap with the
+ // appropriate dimensions.
+ const float sqrt2 = 1.41421356f;
+ const int diagonal_bitmap_size = ceil((bitmap_width + bitmap_height) / sqrt2);
+ FS_RECTF diagonal_bitmap_rect{0, 0, diagonal_bitmap_size,
+ diagonal_bitmap_size};
+ FS_MATRIX rotate_45_scale_2_matrix{
+ sqrt2, sqrt2, -sqrt2, sqrt2, bitmap_height / sqrt2, 0};
+ TestRenderPageBitmapWithMatrix(page, diagonal_bitmap_size,
+ diagonal_bitmap_size, rotate_45_scale_2_matrix,
+ diagonal_bitmap_rect,
+ kLargerRotatedDiagonalMD5);
+
+ // Render the (2, 1) tile of the page (third column, second row) when the page
+ // is divided in 50x50 pixel tiles. The tile is scaled by a factor of 7.
+ const float scale = 7.0;
+ const int tile_size = 50;
+ const int tile_x = 2;
+ const int tile_y = 1;
+ int tile_bitmap_size = scale * tile_size;
+ FS_RECTF tile_bitmap_rect{0, 0, tile_bitmap_size, tile_bitmap_size};
+ FS_MATRIX tile_2_1_matrix{scale,
+ 0,
+ 0,
+ scale,
+ -tile_x * tile_bitmap_size,
+ -tile_y * tile_bitmap_size};
+ TestRenderPageBitmapWithMatrix(page, tile_bitmap_size, tile_bitmap_size,
+ tile_2_1_matrix, tile_bitmap_rect, kTileMD5);
UnloadPage(page);
}