Add experimental FPDFText_SetCharcodes() API.
Instead of calling FPDFText_SetText() and letting it convert the input
text characters to charcodes, allow the caller to set the charcodes
directly.
Bug: pdfium:1705
Change-Id: I1368def473f76e829b622aa75bd11efaad193cf6
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/83491
Commit-Queue: Lei Zhang <thestig@chromium.org>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/fpdfsdk/fpdf_edit_embeddertest.cpp b/fpdfsdk/fpdf_edit_embeddertest.cpp
index 4ea5c14..350d655 100644
--- a/fpdfsdk/fpdf_edit_embeddertest.cpp
+++ b/fpdfsdk/fpdf_edit_embeddertest.cpp
@@ -250,7 +250,7 @@
} // namespace
TEST_F(FPDFEditEmbedderTest, EmbedNotoSansSCFont) {
- EXPECT_TRUE(CreateEmptyDocument());
+ ASSERT_TRUE(CreateEmptyDocument());
ScopedFPDFPage page(FPDFPage_New(document(), 0, 400, 400));
std::string font_path;
ASSERT_TRUE(PathService::GetThirdPartyFilePath(
@@ -259,7 +259,7 @@
size_t file_length = 0;
std::unique_ptr<char, pdfium::FreeDeleter> font_data =
GetFileContents(font_path.c_str(), &file_length);
- DCHECK(font_data);
+ ASSERT_TRUE(font_data);
ScopedFPDFFont font(FPDFText_LoadFont(
document(), reinterpret_cast<const uint8_t*>(font_data.get()),
@@ -280,20 +280,69 @@
#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
#if defined(OS_APPLE)
const char kChecksum[] = "9a31fb87d1c6d2346bba22d1196041cd";
-#else
+#else // defined(OS_APPLE)
const char kChecksum[] = "5bb65e15fc0a685934cd5006dec08a76";
#endif // defined(OS_APPLE)
-#else
+#else // defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
#if defined(OS_WIN)
const char kChecksum[] = "89e8eef5d6ad18c542a92a0519954d0f";
-#else
+#else // defined(OS_WIN)
const char kChecksum[] = "9a31fb87d1c6d2346bba22d1196041cd";
#endif // defined(OS_WIN)
#endif // defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
CompareBitmap(page_bitmap.get(), 400, 400, kChecksum);
- EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+ ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+ VerifySavedDocument(400, 400, kChecksum);
+}
+
+TEST_F(FPDFEditEmbedderTest, EmbedNotoSansSCFontWithCharcodes) {
+ ASSERT_TRUE(CreateEmptyDocument());
+ ScopedFPDFPage page(FPDFPage_New(document(), 0, 400, 400));
+ std::string font_path;
+ ASSERT_TRUE(PathService::GetThirdPartyFilePath(
+ "NotoSansCJK/NotoSansSC-Regular.subset.otf", &font_path));
+
+ size_t file_length = 0;
+ std::unique_ptr<char, pdfium::FreeDeleter> font_data =
+ GetFileContents(font_path.c_str(), &file_length);
+ ASSERT_TRUE(font_data);
+
+ ScopedFPDFFont font(FPDFText_LoadFont(
+ document(), reinterpret_cast<const uint8_t*>(font_data.get()),
+ file_length, FPDF_FONT_TRUETYPE, /*cid=*/true));
+ FPDF_PAGEOBJECT text_object =
+ FPDFPageObj_CreateTextObj(document(), font.get(), 20.0f);
+ EXPECT_TRUE(text_object);
+
+ // Same as `text` in the EmbedNotoSansSCFont test case above.
+ const std::vector<uint32_t> charcodes = {9, 6, 7, 3, 5, 2, 1,
+ 9, 6, 7, 4, 8, 2};
+ EXPECT_TRUE(
+ FPDFText_SetCharcodes(text_object, charcodes.data(), charcodes.size()));
+
+ FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 50, 200);
+ FPDFPage_InsertObject(page.get(), text_object);
+ EXPECT_TRUE(FPDFPage_GenerateContent(page.get()));
+
+#if defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
+#if defined(OS_APPLE)
+ const char kChecksum[] = "9a31fb87d1c6d2346bba22d1196041cd";
+#else // defined(OS_APPLE)
+ const char kChecksum[] = "5bb65e15fc0a685934cd5006dec08a76";
+#endif // defined(OS_APPLE)
+#else // defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
+#if defined(OS_WIN)
+ const char kChecksum[] = "89e8eef5d6ad18c542a92a0519954d0f";
+#else // defined(OS_WIN)
+ const char kChecksum[] = "9a31fb87d1c6d2346bba22d1196041cd";
+#endif // defined(OS_WIN)
+#endif // defined(_SKIA_SUPPORT_) || defined(_SKIA_SUPPORT_PATHS_)
+ ScopedFPDFBitmap page_bitmap = RenderPage(page.get());
+ CompareBitmap(page_bitmap.get(), 400, 400, kChecksum);
+
+ ASSERT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
VerifySavedDocument(400, 400, kChecksum);
}
@@ -749,6 +798,25 @@
CloseSavedDocument();
}
+TEST_F(FPDFEditEmbedderTest, SetCharcodesBadParams) {
+ ASSERT_TRUE(OpenDocument("hello_world.pdf"));
+ FPDF_PAGE page = LoadPage(0);
+ ASSERT_TRUE(page);
+
+ ASSERT_EQ(2, FPDFPage_CountObjects(page));
+ FPDF_PAGEOBJECT page_object = FPDFPage_GetObject(page, 0);
+ ASSERT_TRUE(page_object);
+
+ const uint32_t kDummyValue = 42;
+ EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, nullptr, 0));
+ EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, nullptr, 1));
+ EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, &kDummyValue, 0));
+ EXPECT_FALSE(FPDFText_SetCharcodes(nullptr, &kDummyValue, 1));
+ EXPECT_FALSE(FPDFText_SetCharcodes(page_object, nullptr, 1));
+
+ UnloadPage(page);
+}
+
TEST_F(FPDFEditEmbedderTest, SetTextKeepClippingPath) {
// Load document with some text, with parts clipped.
ASSERT_TRUE(OpenDocument("bug_1558.pdf"));
diff --git a/fpdfsdk/fpdf_edittext.cpp b/fpdfsdk/fpdf_edittext.cpp
index 0f4b7a0..c7fb03c 100644
--- a/fpdfsdk/fpdf_edittext.cpp
+++ b/fpdfsdk/fpdf_edittext.cpp
@@ -482,6 +482,27 @@
return true;
}
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFText_SetCharcodes(FPDF_PAGEOBJECT text_object,
+ const uint32_t* charcodes,
+ size_t count) {
+ CPDF_TextObject* pTextObj = CPDFTextObjectFromFPDFPageObject(text_object);
+ if (!pTextObj)
+ return false;
+
+ if (!charcodes && count)
+ return false;
+
+ ByteString byte_text;
+ if (charcodes) {
+ for (size_t i = 0; i < count; ++i) {
+ pTextObj->GetFont()->AppendChar(&byte_text, charcodes[i]);
+ }
+ }
+ pTextObj->SetText(byte_text);
+ return true;
+}
+
FPDF_EXPORT FPDF_FONT FPDF_CALLCONV FPDFText_LoadFont(FPDF_DOCUMENT document,
const uint8_t* data,
uint32_t size,
diff --git a/fpdfsdk/fpdf_view_c_api_test.c b/fpdfsdk/fpdf_view_c_api_test.c
index de6b15e..c1fdbfa 100644
--- a/fpdfsdk/fpdf_view_c_api_test.c
+++ b/fpdfsdk/fpdf_view_c_api_test.c
@@ -241,6 +241,7 @@
CHK(FPDFTextObj_SetTextRenderMode);
CHK(FPDFText_LoadFont);
CHK(FPDFText_LoadStandardFont);
+ CHK(FPDFText_SetCharcodes);
CHK(FPDFText_SetText);
CHK(FPDF_CreateNewDocument);
diff --git a/public/fpdf_edit.h b/public/fpdf_edit.h
index c0b5282..40bb11f 100644
--- a/public/fpdf_edit.h
+++ b/public/fpdf_edit.h
@@ -1093,7 +1093,7 @@
FPDF_BYTESTRING font,
float font_size);
-// Set the text for a textobject. If it had text, it will be replaced.
+// Set the text for a text object. If it had text, it will be replaced.
//
// text_object - handle to the text object.
// text - the UTF-16LE encoded string containing the text to be added.
@@ -1102,6 +1102,20 @@
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
FPDFText_SetText(FPDF_PAGEOBJECT text_object, FPDF_WIDESTRING text);
+// Experimental API.
+// Set the text using charcodes for a text object. If it had text, it will be
+// replaced.
+//
+// text_object - handle to the text object.
+// charcodes - pointer to an array of charcodes to be added.
+// count - number of elements in |charcodes|.
+//
+// Returns TRUE on success
+FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV
+FPDFText_SetCharcodes(FPDF_PAGEOBJECT text_object,
+ const uint32_t* charcodes,
+ size_t count);
+
// Returns a font object loaded from a stream of data. The font is loaded
// into the document.
//