summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BUILD.gn1
-rw-r--r--core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp63
-rw-r--r--core/fpdfapi/edit/cpdf_pagecontentgenerator.h5
-rw-r--r--core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp89
4 files changed, 156 insertions, 2 deletions
diff --git a/BUILD.gn b/BUILD.gn
index c7266d3a1d..d0946a490d 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -1734,6 +1734,7 @@ if (pdf_enable_xfa) {
test("pdfium_unittests") {
sources = [
"core/fdrm/crypto/fx_crypt_unittest.cpp",
+ "core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp",
"core/fpdfapi/font/fpdf_font_cid_unittest.cpp",
"core/fpdfapi/font/fpdf_font_unittest.cpp",
"core/fpdfapi/page/cpdf_streamcontentparser_unittest.cpp",
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
index a65d564141..e2354e1b50 100644
--- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
+++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
@@ -10,6 +10,8 @@
#include "core/fpdfapi/page/cpdf_image.h"
#include "core/fpdfapi/page/cpdf_imageobject.h"
#include "core/fpdfapi/page/cpdf_page.h"
+#include "core/fpdfapi/page/cpdf_path.h"
+#include "core/fpdfapi/page/cpdf_pathobject.h"
#include "core/fpdfapi/parser/cpdf_dictionary.h"
#include "core/fpdfapi/parser/cpdf_document.h"
#include "core/fpdfapi/parser/cpdf_name.h"
@@ -40,9 +42,10 @@ CPDF_PageContentGenerator::~CPDF_PageContentGenerator() {}
void CPDF_PageContentGenerator::GenerateContent() {
CFX_ByteTextBuf buf;
for (CPDF_PageObject* pPageObj : m_pageObjects) {
- CPDF_ImageObject* pImageObject = pPageObj->AsImage();
- if (pImageObject)
+ if (CPDF_ImageObject* pImageObject = pPageObj->AsImage())
ProcessImage(&buf, pImageObject);
+ else if (CPDF_PathObject* pPathObj = pPageObj->AsPath())
+ ProcessPath(&buf, pPathObj);
}
CPDF_Dictionary* pPageDict = m_pPage->m_pFormDict;
CPDF_Object* pContent =
@@ -109,3 +112,59 @@ void CPDF_PageContentGenerator::ProcessImage(CFX_ByteTextBuf* buf,
*buf << "/" << PDF_NameEncode(name) << " Do Q\n";
}
+
+// Processing path with operators from Tables 4.9 and 4.10 of PDF spec 1.7:
+// "re" appends a rectangle (here, used only if the whole path is a rectangle)
+// "m" moves current point to the given coordinates
+// "l" creates a line from current point to the new point
+// "c" adds a Bezier curve from current to last point, using the two other
+// points as the Bezier control points
+// Note: "l", "c" change the current point
+// "h" closes the subpath (appends a line from current to starting point)
+// Path painting operators: "S", "n", "B", "f", "B*", "f*", depending on
+// the filling mode and whether we want stroking the path or not.
+void CPDF_PageContentGenerator::ProcessPath(CFX_ByteTextBuf* buf,
+ CPDF_PathObject* pPathObj) {
+ const FX_PATHPOINT* pPoints = pPathObj->m_Path.GetPoints();
+ if (pPathObj->m_Path.IsRect()) {
+ *buf << pPoints[0].m_PointX << " " << pPoints[0].m_PointY << " "
+ << (pPoints[2].m_PointX - pPoints[0].m_PointX) << " "
+ << (pPoints[2].m_PointY - pPoints[0].m_PointY) << " re";
+ } else {
+ int numPoints = pPathObj->m_Path.GetPointCount();
+ for (int i = 0; i < numPoints; i++) {
+ if (i > 0)
+ *buf << " ";
+ *buf << pPoints[i].m_PointX << " " << pPoints[i].m_PointY;
+ int pointFlag = pPoints[i].m_Flag;
+ if (pointFlag == FXPT_MOVETO) {
+ *buf << " m";
+ } else if (pointFlag & FXPT_LINETO) {
+ *buf << " l";
+ } else if (pointFlag & FXPT_BEZIERTO) {
+ if (i + 2 >= numPoints || pPoints[i].m_Flag != FXPT_BEZIERTO ||
+ pPoints[i + 1].m_Flag != FXPT_BEZIERTO ||
+ (pPoints[i + 2].m_Flag & FXPT_BEZIERTO) == 0) {
+ // If format is not supported, close the path and paint
+ *buf << " h";
+ break;
+ }
+ *buf << " " << pPoints[i + 1].m_PointX << " " << pPoints[i + 1].m_PointY
+ << " " << pPoints[i + 2].m_PointX << " " << pPoints[i + 2].m_PointY
+ << " c";
+ if (pPoints[i + 2].m_Flag & FXPT_CLOSEFIGURE)
+ *buf << " h";
+ i += 2;
+ }
+ if (pointFlag & FXPT_CLOSEFIGURE)
+ *buf << " h";
+ }
+ }
+ if (pPathObj->m_FillType == 0)
+ *buf << (pPathObj->m_bStroke ? " S" : " n");
+ else if (pPathObj->m_FillType == FXFILL_WINDING)
+ *buf << (pPathObj->m_bStroke ? " B" : " f");
+ else if (pPathObj->m_FillType == FXFILL_ALTERNATE)
+ *buf << (pPathObj->m_bStroke ? " B*" : " f*");
+ *buf << "\n";
+}
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.h b/core/fpdfapi/edit/cpdf_pagecontentgenerator.h
index ac06dcb554..c74652e206 100644
--- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.h
+++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.h
@@ -16,6 +16,7 @@ class CPDF_Document;
class CPDF_ImageObject;
class CPDF_Page;
class CPDF_PageObject;
+class CPDF_PathObject;
class CPDF_PageContentGenerator {
public:
@@ -25,6 +26,10 @@ class CPDF_PageContentGenerator {
void GenerateContent();
private:
+ friend class cpdf_pagecontentgenerator_ProcessRect_Test;
+ friend class cpdf_pagecontentgenerator_ProcessPath_Test;
+
+ void ProcessPath(CFX_ByteTextBuf* buf, CPDF_PathObject* pPathObj);
void ProcessImage(CFX_ByteTextBuf* buf, CPDF_ImageObject* pImageObj);
CFX_ByteString RealizeResource(uint32_t dwResourceObjNum,
const CFX_ByteString& bsType);
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
new file mode 100644
index 0000000000..8812c0e2b6
--- /dev/null
+++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
@@ -0,0 +1,89 @@
+// Copyright 2017 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/fpdfapi/edit/cpdf_pagecontentgenerator.h"
+
+#include "core/fpdfapi/page/cpdf_page.h"
+#include "core/fpdfapi/page/cpdf_pathobject.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/base/ptr_util.h"
+
+TEST(cpdf_pagecontentgenerator, ProcessRect) {
+ auto pPathObj = pdfium::MakeUnique<CPDF_PathObject>();
+ pPathObj->m_Path.AppendRect(10, 5, 13, 30);
+ pPathObj->m_FillType = FXFILL_ALTERNATE;
+ pPathObj->m_bStroke = true;
+ auto pTestPage = pdfium::MakeUnique<CPDF_Page>(nullptr, nullptr, false);
+ CPDF_PageContentGenerator generator(pTestPage.get());
+ CFX_ByteTextBuf buf;
+ generator.ProcessPath(&buf, pPathObj.get());
+ EXPECT_EQ("10 5 3 25 re B*\n", buf.MakeString());
+
+ pPathObj = pdfium::MakeUnique<CPDF_PathObject>();
+ pPathObj->m_Path.SetPointCount(4);
+ FX_PATHPOINT* pPoints = pPathObj->m_Path.GetMutablePoints();
+ pPoints[0].m_PointX = 0;
+ pPoints[0].m_PointY = 0;
+ pPoints[0].m_Flag = FXPT_MOVETO;
+ pPoints[1].m_PointX = 5.2f;
+ pPoints[1].m_PointY = 0;
+ pPoints[1].m_Flag = FXPT_LINETO;
+ pPoints[2].m_PointX = 5.2f;
+ pPoints[2].m_PointY = 3.78f;
+ pPoints[2].m_Flag = FXPT_LINETO;
+ pPoints[3].m_PointX = 0;
+ pPoints[3].m_PointY = 3.78f;
+ pPoints[3].m_Flag = FXPT_LINETO | FXPT_CLOSEFIGURE;
+ pPathObj->m_FillType = 0;
+ pPathObj->m_bStroke = false;
+ buf.Clear();
+ generator.ProcessPath(&buf, pPathObj.get());
+ EXPECT_EQ("0 0 5.2 3.78 re n\n", buf.MakeString());
+}
+
+TEST(cpdf_pagecontentgenerator, ProcessPath) {
+ auto pPathObj = pdfium::MakeUnique<CPDF_PathObject>();
+ pPathObj->m_Path.SetPointCount(10);
+ FX_PATHPOINT* pPoints = pPathObj->m_Path.GetMutablePoints();
+ pPoints[0].m_PointX = 3.102f;
+ pPoints[0].m_PointY = 4.67f;
+ pPoints[0].m_Flag = FXPT_MOVETO;
+ pPoints[1].m_PointX = 5.45f;
+ pPoints[1].m_PointY = 0.29f;
+ pPoints[1].m_Flag = FXPT_LINETO;
+ pPoints[2].m_PointX = 4.24f;
+ pPoints[2].m_PointY = 3.15f;
+ pPoints[2].m_Flag = FXPT_BEZIERTO;
+ pPoints[3].m_PointX = 4.65f;
+ pPoints[3].m_PointY = 2.98f;
+ pPoints[3].m_Flag = FXPT_BEZIERTO;
+ pPoints[4].m_PointX = 3.456f;
+ pPoints[4].m_PointY = 0.24f;
+ pPoints[4].m_Flag = FXPT_BEZIERTO;
+ pPoints[5].m_PointX = 10.6f;
+ pPoints[5].m_PointY = 11.15f;
+ pPoints[5].m_Flag = FXPT_LINETO;
+ pPoints[6].m_PointX = 11;
+ pPoints[6].m_PointY = 12.5f;
+ pPoints[6].m_Flag = FXPT_LINETO;
+ pPoints[7].m_PointX = 11.46f;
+ pPoints[7].m_PointY = 12.67f;
+ pPoints[7].m_Flag = FXPT_BEZIERTO;
+ pPoints[8].m_PointX = 11.84f;
+ pPoints[8].m_PointY = 12.96f;
+ pPoints[8].m_Flag = FXPT_BEZIERTO;
+ pPoints[9].m_PointX = 12;
+ pPoints[9].m_PointY = 13.64f;
+ pPoints[9].m_Flag = FXPT_BEZIERTO | FXPT_CLOSEFIGURE;
+ pPathObj->m_FillType = FXFILL_WINDING;
+ pPathObj->m_bStroke = false;
+ auto pTestPage = pdfium::MakeUnique<CPDF_Page>(nullptr, nullptr, false);
+ CPDF_PageContentGenerator generator(pTestPage.get());
+ CFX_ByteTextBuf buf;
+ generator.ProcessPath(&buf, pPathObj.get());
+ EXPECT_EQ(
+ "3.102 4.67 m 5.45 0.29 l 4.24 3.15 4.65 2.98 3.456 0.24 c 10.6 11.15 l "
+ "11 12.5 l 11.46 12.67 11.84 12.96 12 13.64 c h f\n",
+ buf.MakeString());
+}