Generate clipping path when processing the graphics of page objects
When reprocessing the graphics of an edited/dirty page object, the
clipping path is ignored. Keep those clipping paths instead.
Bug: pdfium:1558
Change-Id: Idead22cbf7796a8971e3af164464d8c80956d1e7
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/71713
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Daniel Hosseinian <dhoss@chromium.org>
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
index 573b40c..b07622a 100644
--- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
+++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
@@ -404,6 +404,8 @@
// "rg" sets the fill color, "RG" sets the stroke color (using DefaultRGB)
// "w" sets the stroke line width.
// "ca" sets the fill alpha, "CA" sets the stroke alpha.
+// "W" and "W*" modify the clipping path using the nonzero winding rule and
+// even-odd rules, respectively.
// "q" saves the graphics state, so that the settings can later be reversed
void CPDF_PageContentGenerator::ProcessGraphics(std::ostringstream* buf,
CPDF_PageObject* pPageObj) {
@@ -428,6 +430,29 @@
if (lineJoin != CFX_GraphStateData::LineJoinMiter)
*buf << static_cast<int>(lineJoin) << " j ";
+ const CPDF_ClipPath& clip_path = pPageObj->m_ClipPath;
+ if (clip_path.HasRef()) {
+ for (size_t i = 0; i < clip_path.GetPathCount(); ++i) {
+ CPDF_Path path = clip_path.GetPath(i);
+ ProcessPathPoints(buf, &path);
+ switch (clip_path.GetClipType(i)) {
+ case CFX_FillRenderOptions::FillType::kWinding:
+ *buf << " W ";
+ break;
+ case CFX_FillRenderOptions::FillType::kEvenOdd:
+ *buf << " W* ";
+ break;
+ case CFX_FillRenderOptions::FillType::kNoFill:
+ NOTREACHED();
+ break;
+ }
+
+ // Use a no-op path-painting operator to terminate the path without
+ // causing any marks to be placed on the page.
+ *buf << "n 0 g ";
+ }
+ }
+
GraphicsData graphD;
graphD.fillAlpha = pPageObj->m_GeneralState.GetFillAlpha();
graphD.strokeAlpha = pPageObj->m_GeneralState.GetStrokeAlpha();
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
index c3fe7f0..5e145b2 100644
--- a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
+++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
@@ -331,6 +331,18 @@
pTextObj->m_TextState.SetFontSize(15.5f);
pTextObj->SetText("I am indirect");
pTextObj->SetTextRenderMode(TextRenderingMode::MODE_FILL_CLIP);
+
+ // Add a clipping path.
+ auto pPath = std::make_unique<CPDF_Path>();
+ pPath->AppendPoint(CFX_PointF(0, 0), FXPT_TYPE::MoveTo);
+ pPath->AppendPoint(CFX_PointF(5, 0), FXPT_TYPE::LineTo);
+ pPath->AppendPoint(CFX_PointF(5, 4), FXPT_TYPE::LineTo);
+ pPath->AppendPointAndClose(CFX_PointF(0, 4), FXPT_TYPE::LineTo);
+ pTextObj->m_ClipPath.Emplace();
+ pTextObj->m_ClipPath.AppendPath(*pPath,
+ CFX_FillRenderOptions::FillType::kEvenOdd,
+ /*bAutoMerge=*/false);
+
TestProcessText(&generator, &buf, pTextObj.get());
}
@@ -342,7 +354,7 @@
ByteString lastString =
textString.Last(textString.GetLength() - firstResourceAt.value());
// q and Q must be outside the BT .. ET operations
- ByteString compareString1 = "q BT 1 0 0 1 0 0 Tm /";
+ ByteString compareString1 = "q 0 0 5 4 re W* n 0 g BT 1 0 0 1 0 0 Tm /";
ByteString compareString2 =
" 15.5 Tf 4 Tr <4920616D20696E646972656374> Tj ET Q\n";
EXPECT_LT(compareString1.GetLength() + compareString2.GetLength(),
diff --git a/fpdfsdk/fpdf_edit_embeddertest.cpp b/fpdfsdk/fpdf_edit_embeddertest.cpp
index 0cdcb9f..6371efc 100644
--- a/fpdfsdk/fpdf_edit_embeddertest.cpp
+++ b/fpdfsdk/fpdf_edit_embeddertest.cpp
@@ -658,8 +658,6 @@
CloseSavedDocument();
}
-// TODO(crbug.com/pdfium/1558): Clipping paths should be retained after saving
-// changed text.
TEST_F(FPDFEditEmbedderTest, SetTextKeepClippingPath) {
// Load document with some text, with parts clipped.
ASSERT_TRUE(OpenDocument("bug_1558.pdf"));
@@ -718,17 +716,8 @@
ASSERT_TRUE(saved_page);
{
- static constexpr char kChangedChecksum[] =
-#if defined(OS_WIN)
- "da44e0c040ed56dbb60cf44ef033757b";
-#elif defined(OS_MACOSX)
- "0bfd2dab51dd588a7f77d531582078cd";
-#else
- "e63e78fcbcfba4b64f2b843fdf2cc3e8";
-#endif
- // The checksum of |saved_bitmap| should be |kOriginalChecksum|.
ScopedFPDFBitmap saved_bitmap = RenderSavedPage(saved_page);
- CompareBitmap(saved_bitmap.get(), 200, 200, kChangedChecksum);
+ CompareBitmap(saved_bitmap.get(), 200, 200, kOriginalChecksum);
}
CloseSavedPage(saved_page);