summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/fpdfapi/page/cpdf_page.cpp29
-rw-r--r--core/fpdfapi/page/cpdf_page.h7
-rw-r--r--fpdfsdk/fpdfview.cpp16
-rw-r--r--fpdfsdk/fpdfview_embeddertest.cpp113
-rw-r--r--public/fpdfview.h4
-rw-r--r--testing/resources/rectangles.in14
-rw-r--r--testing/resources/rectangles.pdf16
7 files changed, 142 insertions, 57 deletions
diff --git a/core/fpdfapi/page/cpdf_page.cpp b/core/fpdfapi/page/cpdf_page.cpp
index dfbd342f13..6213e5fccb 100644
--- a/core/fpdfapi/page/cpdf_page.cpp
+++ b/core/fpdfapi/page/cpdf_page.cpp
@@ -178,6 +178,35 @@ 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 1891e651be..47fba3caec 100644
--- a/core/fpdfapi/page/cpdf_page.h
+++ b/core/fpdfapi/page/cpdf_page.h
@@ -38,11 +38,16 @@ 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; }
CFX_FloatRect GetPageBBox() const { return m_BBox; }
- const CFX_Matrix& GetPageMatrix() const { return m_PageMatrix; }
int GetPageRotation() const;
CPDF_PageRenderCache* GetRenderCache() const { return m_pPageRender.get(); }
diff --git a/fpdfsdk/fpdfview.cpp b/fpdfsdk/fpdfview.cpp
index e93e8bcd58..5bcc643ac1 100644
--- a/fpdfsdk/fpdfview.cpp
+++ b/fpdfsdk/fpdfview.cpp
@@ -1004,15 +1004,13 @@ FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap,
clipping_rect.top = clipping->top;
}
FX_RECT clip_rect = clipping_rect.ToFxRect();
-
- CFX_Matrix transform_matrix = pPage->GetDisplayMatrix(
- clip_rect.left, clip_rect.top, clip_rect.Width(), clip_rect.Height(), 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);
+ 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);
pPage->SetRenderContext(nullptr);
}
diff --git a/fpdfsdk/fpdfview_embeddertest.cpp b/fpdfsdk/fpdfview_embeddertest.cpp
index 8576104c2e..97ba9d7c4c 100644
--- a/fpdfsdk/fpdfview_embeddertest.cpp
+++ b/fpdfsdk/fpdfview_embeddertest.cpp
@@ -5,6 +5,7 @@
#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"
@@ -350,75 +351,119 @@ TEST_F(FPDFViewEmbeddertest, Hang_360) {
}
TEST_F(FPDFViewEmbeddertest, FPDF_RenderPageBitmapWithMatrix) {
- const char kOriginalMD5[] = "210157942bcce97b057a1107a1fd62f8";
- const char kTopLeftQuarterMD5[] = "c54d58dda13e3cd04eb63e1d0db0feda";
- const char kTrimmedMD5[] = "88225d7951a21d0eef191cfed06c36ce";
- const char kRotatedMD5[] = "7d38bc58aa50ad271bc432e77256d3de";
+ const char* const kRotatedMD5[4] = {
+ "0a90de37f52127619c3dfb642b5fa2fe", "d599429574ff0dcad3bc898ea8b874ca",
+ "0113386bb0bd45125bacc6dee78bfe78", "051fcfa4c1f9de28765705633a8ef3a9"};
+ const char kTopLeftQuarterMD5[] = "4982be08db3f6d2e6409186ebbced9eb";
+ const char kHoriStretchedMD5[] = "004bf38f3c5c76a644e6fca204747f21";
+ const char kRotateandStretchMD5[] = "0ea95cacc716d003cf063a2c5ed6c8d7";
EXPECT_TRUE(OpenDocument("rectangles.pdf"));
FPDF_PAGE page = LoadPage(0);
EXPECT_NE(nullptr, page);
- const int width = static_cast<int>(FPDF_GetPageWidth(page));
- const int height = static_cast<int>(FPDF_GetPageHeight(page));
- EXPECT_EQ(200, width);
- EXPECT_EQ(200, height);
+ 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);
FPDF_BITMAP bitmap = RenderPage(page);
- CompareBitmap(bitmap, width, height, kOriginalMD5);
+ CompareBitmap(bitmap, initial_width, initial_height, kRotatedMD5[0]);
FPDFBitmap_Destroy(bitmap);
- // Try rendering with an identity matrix. The output should be the same as
- // the RenderPage() output.
- FS_MATRIX matrix;
- matrix.a = 1;
- matrix.b = 0;
- matrix.c = 0;
- matrix.d = 1;
- matrix.e = 0;
- matrix.f = 0;
-
+ int width;
+ int height;
FS_RECTF rect;
rect.left = 0;
rect.top = 0;
- rect.right = width;
- rect.bottom = height;
+ FS_MATRIX matrix;
- 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, 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).
+ rect.right = initial_width;
+ rect.bottom = 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) {
+ 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.
+ width = initial_width / 2;
+ height = initial_height / 2;
matrix.a = 0.5;
+ matrix.b = 0;
+ matrix.c = 0;
matrix.d = 0.5;
+ 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, kTopLeftQuarterMD5);
FPDFBitmap_Destroy(bitmap);
- // Now render again with the image scaled larger horizontally (will be
- // trimmed).
+ // 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, kTrimmedMD5);
+ CompareBitmap(bitmap, width, height, kHoriStretchedMD5);
FPDFBitmap_Destroy(bitmap);
- // Now try a 90 degree rotation
+ // Test a rotation followed by a stretch.
+ width = initial_height * 2;
+ height = initial_width;
matrix.a = 0;
- matrix.b = 1;
- matrix.c = -1;
+ matrix.b = -1;
+ matrix.c = 2;
matrix.d = 0;
- matrix.e = width;
+ 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, kRotatedMD5);
+ CompareBitmap(bitmap, width, height, kRotateandStretchMD5);
FPDFBitmap_Destroy(bitmap);
UnloadPage(page);
diff --git a/public/fpdfview.h b/public/fpdfview.h
index c74fcb99d0..135d00a8f4 100644
--- a/public/fpdfview.h
+++ b/public/fpdfview.h
@@ -666,7 +666,7 @@ FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap,
// by FPDFBitmap_Create or retrieved by
// FPDFImageObj_GetBitmap.
// page - Handle to the page. Returned by FPDF_LoadPage
-// matrix - The transform matrix.
+// matrix - The transform matrix. It must be invertible.
// clipping - The rect to clip to.
// flags - 0 for normal display, or combination of the Page
// Rendering flags defined above. With the FPDF_ANNOT
@@ -674,7 +674,7 @@ FPDF_EXPORT void FPDF_CALLCONV FPDF_RenderPageBitmap(FPDF_BITMAP bitmap,
// user-interaction, which are all annotations except
// widget and popup annotations.
// Return value:
-// None.
+// None. Note that behavior is undefined if det of |matrix| is 0.
FPDF_EXPORT void FPDF_CALLCONV
FPDF_RenderPageBitmapWithMatrix(FPDF_BITMAP bitmap,
FPDF_PAGE page,
diff --git a/testing/resources/rectangles.in b/testing/resources/rectangles.in
index ed71cf830a..49932fff2a 100644
--- a/testing/resources/rectangles.in
+++ b/testing/resources/rectangles.in
@@ -6,7 +6,7 @@
endobj
{{object 2 0}} <<
/Type /Pages
- /MediaBox [ 0 0 200 200 ]
+ /MediaBox [ 0 0 200 300 ]
/Count 1
/Kids [ 3 0 R ]
>>
@@ -22,13 +22,17 @@ endobj
stream
q
0 0 0 rg
-10 80 50 30 re B*
+0 290 10 10 re B*
+10 150 50 30 re B*
0 0 1 rg
-70 135 50 30 re B*
+190 290 10 10 re B*
+70 232 50 30 re B*
0 1 0 rg
-130 80 50 30 re B*
+190 0 10 10 re B*
+130 150 50 30 re B*
1 0 0 rg
-70 25 50 30 re B*
+0 0 10 10 re B*
+70 67 50 30 re B*
Q
endstream
endobj
diff --git a/testing/resources/rectangles.pdf b/testing/resources/rectangles.pdf
index 718bee56d9..7bad251ba7 100644
--- a/testing/resources/rectangles.pdf
+++ b/testing/resources/rectangles.pdf
@@ -7,7 +7,7 @@
endobj
2 0 obj <<
/Type /Pages
- /MediaBox [ 0 0 200 200 ]
+ /MediaBox [ 0 0 200 300 ]
/Count 1
/Kids [ 3 0 R ]
>>
@@ -23,13 +23,17 @@ endobj
stream
q
0 0 0 rg
-10 80 50 30 re B*
+0 290 10 10 re B*
+10 150 50 30 re B*
0 0 1 rg
-70 135 50 30 re B*
+190 290 10 10 re B*
+70 232 50 30 re B*
0 1 0 rg
-130 80 50 30 re B*
+190 0 10 10 re B*
+130 150 50 30 re B*
1 0 0 rg
-70 25 50 30 re B*
+0 0 10 10 re B*
+70 67 50 30 re B*
Q
endstream
endobj
@@ -42,5 +46,5 @@ xref
0000000230 00000 n
trailer<< /Root 1 0 R /Size 5 >>
startxref
-382
+456
%%EOF