Fix FPDFTextObj_SetTextRenderMode() to stick when the document is saved
CPDF_PageContentGenerator::ProcessText() neglected to set the text
rendering mode in the content stream.
Bug: pdfium:1470
Change-Id: I507109cf65b35ce491342d59fc0f37309f9a9d21
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/71092
Commit-Queue: Daniel Hosseinian <dhoss@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
index 34dde67..580b36e 100644
--- a/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
+++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator.cpp
@@ -488,6 +488,7 @@
// This method adds text to the buffer, BT begins the text object, ET ends it.
// Tm sets the text matrix (allows positioning and transforming text).
// Tf sets the font name (from Font in Resources) and font size.
+// Tr sets the text rendering mode.
// Tj sets the actual text, <####...> is used when specifying charcodes.
void CPDF_PageContentGenerator::ProcessText(std::ostringstream* buf,
CPDF_TextObject* pTextObj) {
@@ -534,6 +535,7 @@
}
*buf << "/" << PDF_NameEncode(dictName) << " ";
WriteFloat(*buf, pTextObj->GetFontSize()) << " Tf ";
+ *buf << static_cast<int>(pTextObj->GetTextRenderMode()) << " Tr ";
ByteString text;
for (uint32_t charcode : pTextObj->GetCharCodes()) {
if (charcode != CPDF_Font::kInvalidCharCode)
diff --git a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
index f21d449..60f5057 100644
--- a/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
+++ b/core/fpdfapi/edit/cpdf_pagecontentgenerator_unittest.cpp
@@ -15,6 +15,7 @@
#include "core/fpdfapi/page/cpdf_pagemodule.h"
#include "core/fpdfapi/page/cpdf_pathobject.h"
#include "core/fpdfapi/page/cpdf_textobject.h"
+#include "core/fpdfapi/page/cpdf_textstate.h"
#include "core/fpdfapi/parser/cpdf_dictionary.h"
#include "core/fpdfapi/parser/cpdf_document.h"
#include "core/fpdfapi/parser/cpdf_name.h"
@@ -274,7 +275,7 @@
"q 0.501961 0.701961 0.34902 rg 1 0.901961 0 RG /";
// Color RGB values used are integers divided by 255.
ByteString compareString2 = " gs BT 1 0 0 1 100 100 Tm /";
- ByteString compareString3 = " 10 Tf <48656C6C6F20576F726C64> Tj ET Q\n";
+ ByteString compareString3 = " 10 Tf 0 Tr <48656C6C6F20576F726C64> Tj ET Q\n";
EXPECT_LT(compareString1.GetLength() + compareString2.GetLength() +
compareString3.GetLength(),
textString.GetLength());
@@ -329,6 +330,7 @@
pTextObj->m_TextState.SetFont(pLoadedFont);
pTextObj->m_TextState.SetFontSize(15.5f);
pTextObj->SetText("I am indirect");
+ pTextObj->SetTextRenderMode(TextRenderingMode::MODE_FILL_CLIP);
TestProcessText(&generator, &buf, pTextObj.get());
}
@@ -341,7 +343,8 @@
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 compareString2 = " 15.5 Tf <4920616D20696E646972656374> Tj ET Q\n";
+ ByteString compareString2 =
+ " 15.5 Tf 4 Tr <4920616D20696E646972656374> Tj ET Q\n";
EXPECT_LT(compareString1.GetLength() + compareString2.GetLength(),
textString.GetLength());
EXPECT_EQ(compareString1, textString.First(compareString1.GetLength()));
diff --git a/core/fpdfapi/page/cpdf_textobject.cpp b/core/fpdfapi/page/cpdf_textobject.cpp
index 3872a2c..beb3ce9 100644
--- a/core/fpdfapi/page/cpdf_textobject.cpp
+++ b/core/fpdfapi/page/cpdf_textobject.cpp
@@ -258,6 +258,7 @@
void CPDF_TextObject::SetTextRenderMode(TextRenderingMode mode) {
m_TextState.SetTextMode(mode);
+ SetDirty(true);
}
CFX_PointF CPDF_TextObject::CalcPositionData(float horz_scale) {
diff --git a/fpdfsdk/fpdf_edit_embeddertest.cpp b/fpdfsdk/fpdf_edit_embeddertest.cpp
index cb7c8fb..cffeb7c 100644
--- a/fpdfsdk/fpdf_edit_embeddertest.cpp
+++ b/fpdfsdk/fpdf_edit_embeddertest.cpp
@@ -2122,27 +2122,27 @@
CompareBitmap(page_bitmap.get(), 612, 446, md5_stroke);
}
+ // Save a copy.
+ EXPECT_TRUE(FPDFPage_GenerateContent(page));
+ EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+
UnloadPage(page);
}
{
- // Save a copy, open the copy, and render it.
- // Note that the text render mode should be set to
- // |FPDF_TEXTRENDERMODE_STROKE|, but isn't.
- // TODO(crbug.com/pdfium/1470): Fix FPDFTextObj_SetTextRenderMode() to work
- // on saved documents.
- EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+ // Open the saved copy and render it. Check that the changed text render
+ // mode is kept in the saved copy.
ASSERT_TRUE(OpenSavedDocument());
FPDF_PAGE saved_page = LoadSavedPage(0);
ASSERT_TRUE(saved_page);
FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(saved_page, 0);
EXPECT_TRUE(page_object);
- EXPECT_EQ(FPDF_TEXTRENDERMODE_FILL,
+ EXPECT_EQ(FPDF_TEXTRENDERMODE_STROKE,
FPDFTextObj_GetTextRenderMode(page_object));
ScopedFPDFBitmap bitmap = RenderSavedPage(saved_page);
- CompareBitmap(bitmap.get(), 612, 446, md5);
+ CompareBitmap(bitmap.get(), 612, 446, md5_stroke);
CloseSavedPage(saved_page);
CloseSavedDocument();