Add API to create a text object using a loaded font.

There is already a method to add text from standard font, this CL adds
an option to add text using a loaded font. The font set into a text object
is ref counted and may be released, so call LoadFont on this new text obj,
and add a method to close the font. This CL also improves the SetText method
so that it now uses a WideString, in preparation for CID fonts with non-Latin
characters.

Bug: pdfium:667
Change-Id: I6829d702357d2a898a12f5297e4fd2ec993a9891
Reviewed-on: https://pdfium-review.googlesource.com/4770
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Nicolás Peña <npm@chromium.org>
diff --git a/fpdfsdk/fpdfedit_embeddertest.cpp b/fpdfsdk/fpdfedit_embeddertest.cpp
index d62f5ca..4bf68cf 100644
--- a/fpdfsdk/fpdfedit_embeddertest.cpp
+++ b/fpdfsdk/fpdfedit_embeddertest.cpp
@@ -14,6 +14,7 @@
 #include "core/fpdfapi/parser/cpdf_stream.h"
 #include "core/fxcrt/fx_system.h"
 #include "fpdfsdk/fsdk_define.h"
+#include "public/cpp/fpdf_deleters.h"
 #include "public/fpdf_edit.h"
 #include "public/fpdfview.h"
 #include "testing/embedder_test.h"
@@ -423,11 +424,14 @@
   FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
 
   // Add some text to the page
-  FPDF_PAGEOBJECT text1 = FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
-  EXPECT_TRUE(text1);
-  EXPECT_TRUE(FPDFText_SetText(text1, "I'm at the bottom of the page"));
-  FPDFPageObj_Transform(text1, 1, 0, 0, 1, 20, 20);
-  FPDFPage_InsertObject(page, text1);
+  FPDF_PAGEOBJECT text_object1 =
+      FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
+  EXPECT_TRUE(text_object1);
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text1 =
+      GetFPDFWideString(L"I'm at the bottom of the page");
+  EXPECT_TRUE(FPDFText_SetText(text_object1, text1.get()));
+  FPDFPageObj_Transform(text_object1, 1, 0, 0, 1, 20, 20);
+  FPDFPage_InsertObject(page, text_object1);
   EXPECT_TRUE(FPDFPage_GenerateContent(page));
   FPDF_BITMAP page_bitmap = RenderPage(page);
 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
@@ -439,12 +443,14 @@
   FPDFBitmap_Destroy(page_bitmap);
 
   // Try another font
-  FPDF_PAGEOBJECT text2 =
+  FPDF_PAGEOBJECT text_object2 =
       FPDFPageObj_NewTextObj(document(), "TimesNewRomanBold", 15.0f);
-  EXPECT_TRUE(text2);
-  EXPECT_TRUE(FPDFText_SetText(text2, "Hi, I'm Bold. Times New Roman Bold."));
-  FPDFPageObj_Transform(text2, 1, 0, 0, 1, 100, 600);
-  FPDFPage_InsertObject(page, text2);
+  EXPECT_TRUE(text_object2);
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text2 =
+      GetFPDFWideString(L"Hi, I'm Bold. Times New Roman Bold.");
+  EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
+  FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 100, 600);
+  FPDFPage_InsertObject(page, text_object2);
   EXPECT_TRUE(FPDFPage_GenerateContent(page));
   page_bitmap = RenderPage(page);
 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
@@ -458,12 +464,14 @@
   FPDFBitmap_Destroy(page_bitmap);
 
   // And some randomly transformed text
-  FPDF_PAGEOBJECT text3 =
+  FPDF_PAGEOBJECT text_object3 =
       FPDFPageObj_NewTextObj(document(), "Courier-Bold", 20.0f);
-  EXPECT_TRUE(text3);
-  EXPECT_TRUE(FPDFText_SetText(text3, "Can you read me? <:)>"));
-  FPDFPageObj_Transform(text3, 1, 1.5, 2, 0.5, 200, 200);
-  FPDFPage_InsertObject(page, text3);
+  EXPECT_TRUE(text_object3);
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text3 =
+      GetFPDFWideString(L"Can you read me? <:)>");
+  EXPECT_TRUE(FPDFText_SetText(text_object3, text3.get()));
+  FPDFPageObj_Transform(text_object3, 1, 1.5, 2, 0.5, 200, 200);
+  FPDFPage_InsertObject(page, text_object3);
   EXPECT_TRUE(FPDFPage_GenerateContent(page));
   page_bitmap = RenderPage(page);
 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
@@ -522,10 +530,13 @@
   FPDFBitmap_Destroy(page_bitmap);
 
   // Add some text to the page
-  FPDF_PAGEOBJECT text = FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
-  EXPECT_TRUE(FPDFText_SetText(text, "Something something #text# something"));
-  FPDFPageObj_Transform(text, 1, 0, 0, 1, 300, 300);
-  FPDFPage_InsertObject(page, text);
+  FPDF_PAGEOBJECT text_object =
+      FPDFPageObj_NewTextObj(document(), "Arial", 12.0f);
+  std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
+      GetFPDFWideString(L"Something something #text# something");
+  EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
+  FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 300, 300);
+  FPDFPage_InsertObject(page, text_object);
   EXPECT_TRUE(FPDFPage_GenerateContent(page));
   CPDF_Dictionary* font_dict = the_page->m_pResources->GetDictFor("Font");
   ASSERT_TRUE(font_dict);
@@ -545,10 +556,10 @@
       CPDF_Font::GetStockFont(cpdf_doc(), "Times-Bold");
   const uint8_t* data = stock_font->m_Font.GetFontData();
   const uint32_t size = stock_font->m_Font.GetSize();
-  FPDF_FONT font =
-      FPDFText_LoadFont(document(), data, size, FPDF_FONT_TYPE1, false);
-  ASSERT_TRUE(font);
-  CPDF_Font* typed_font = reinterpret_cast<CPDF_Font*>(font);
+  std::unique_ptr<void, FPDFFontDeleter> font(
+      FPDFText_LoadFont(document(), data, size, FPDF_FONT_TYPE1, false));
+  ASSERT_TRUE(font.get());
+  CPDF_Font* typed_font = reinterpret_cast<CPDF_Font*>(font.get());
   EXPECT_TRUE(typed_font->IsType1Font());
 
   CPDF_Dictionary* font_dict = typed_font->GetFontDict();
@@ -574,10 +585,10 @@
   const CPDF_Font* stock_font = CPDF_Font::GetStockFont(cpdf_doc(), "Courier");
   const uint8_t* data = stock_font->m_Font.GetFontData();
   const uint32_t size = stock_font->m_Font.GetSize();
-  FPDF_FONT font =
-      FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, false);
-  ASSERT_TRUE(font);
-  CPDF_Font* typed_font = reinterpret_cast<CPDF_Font*>(font);
+  std::unique_ptr<void, FPDFFontDeleter> font(
+      FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, false));
+  ASSERT_TRUE(font.get());
+  CPDF_Font* typed_font = reinterpret_cast<CPDF_Font*>(font.get());
   EXPECT_TRUE(typed_font->IsTrueTypeFont());
 
   CPDF_Dictionary* font_dict = typed_font->GetFontDict();
@@ -604,10 +615,10 @@
       CPDF_Font::GetStockFont(cpdf_doc(), "Times-Roman");
   const uint8_t* data = stock_font->m_Font.GetFontData();
   const uint32_t size = stock_font->m_Font.GetSize();
-  FPDF_FONT font =
-      FPDFText_LoadFont(document(), data, size, FPDF_FONT_TYPE1, 1);
-  ASSERT_TRUE(font);
-  CPDF_Font* typed_font = reinterpret_cast<CPDF_Font*>(font);
+  std::unique_ptr<void, FPDFFontDeleter> font(
+      FPDFText_LoadFont(document(), data, size, FPDF_FONT_TYPE1, 1));
+  ASSERT_TRUE(font.get());
+  CPDF_Font* typed_font = reinterpret_cast<CPDF_Font*>(font.get());
   EXPECT_TRUE(typed_font->IsCIDFont());
 
   // Check font dictionary entries
@@ -660,10 +671,10 @@
   const uint8_t* data = stock_font->m_Font.GetFontData();
   const uint32_t size = stock_font->m_Font.GetSize();
 
-  FPDF_FONT font =
-      FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 1);
-  ASSERT_TRUE(font);
-  CPDF_Font* typed_font = reinterpret_cast<CPDF_Font*>(font);
+  std::unique_ptr<void, FPDFFontDeleter> font(
+      FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 1));
+  ASSERT_TRUE(font.get());
+  CPDF_Font* typed_font = reinterpret_cast<CPDF_Font*>(font.get());
   EXPECT_TRUE(typed_font->IsCIDFont());
 
   // Check font dictionary entries
@@ -704,3 +715,74 @@
   EXPECT_EQ(3, FPDFPage_GetRotation(page));
   UnloadPage(page);
 }
+
+TEST_F(FPDFEditEmbeddertest, AddTrueTypeFontText) {
+  // Start with a blank page
+  FPDF_PAGE page = FPDFPage_New(CreateNewDocument(), 0, 612, 792);
+  {
+    const CPDF_Font* stock_font = CPDF_Font::GetStockFont(cpdf_doc(), "Arial");
+    const uint8_t* data = stock_font->m_Font.GetFontData();
+    const uint32_t size = stock_font->m_Font.GetSize();
+    std::unique_ptr<void, FPDFFontDeleter> font(
+        FPDFText_LoadFont(document(), data, size, FPDF_FONT_TRUETYPE, 0));
+    ASSERT_TRUE(font.get());
+
+    // Add some text to the page
+    FPDF_PAGEOBJECT text_object =
+        FPDFPageObj_CreateTextObj(document(), font.get(), 12.0f);
+    EXPECT_TRUE(text_object);
+    std::unique_ptr<unsigned short, pdfium::FreeDeleter> text =
+        GetFPDFWideString(L"I am testing my loaded font, WEE.");
+    EXPECT_TRUE(FPDFText_SetText(text_object, text.get()));
+    FPDFPageObj_Transform(text_object, 1, 0, 0, 1, 400, 400);
+    FPDFPage_InsertObject(page, text_object);
+    EXPECT_TRUE(FPDFPage_GenerateContent(page));
+    FPDF_BITMAP page_bitmap = RenderPage(page);
+#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
+    const char md5[] = "17d2b6cd574cf66170b09c8927529a94";
+#else
+    const char md5[] = "28e5b10743660dcdfd1618db47b39d32";
+#endif  // _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
+    CompareBitmap(page_bitmap, 612, 792, md5);
+    FPDFBitmap_Destroy(page_bitmap);
+
+    // Add some more text, same font
+    FPDF_PAGEOBJECT text_object2 =
+        FPDFPageObj_CreateTextObj(document(), font.get(), 15.0f);
+    std::unique_ptr<unsigned short, pdfium::FreeDeleter> text2 =
+        GetFPDFWideString(L"Bigger font size");
+    EXPECT_TRUE(FPDFText_SetText(text_object2, text2.get()));
+    FPDFPageObj_Transform(text_object2, 1, 0, 0, 1, 200, 200);
+    FPDFPage_InsertObject(page, text_object2);
+    EXPECT_TRUE(FPDFPage_GenerateContent(page));
+  }
+  FPDF_BITMAP page_bitmap2 = RenderPage(page);
+#if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
+  const char md5_2[] = "8eded4193ff1f0f77b8b600a825e97ea";
+#else
+  const char md5_2[] = "a068eef4110d607f77c87ea8340fa2a5";
+#endif  // _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
+  CompareBitmap(page_bitmap2, 612, 792, md5_2);
+  FPDFBitmap_Destroy(page_bitmap2);
+
+  EXPECT_TRUE(FPDF_SaveAsCopy(document(), this, 0));
+  FPDF_ClosePage(page);
+  std::string new_file = GetString();
+
+  // Render the saved result
+  FPDF_FILEACCESS file_access;
+  memset(&file_access, 0, sizeof(file_access));
+  file_access.m_FileLen = new_file.size();
+  file_access.m_GetBlock = GetBlockFromString;
+  file_access.m_Param = &new_file;
+  FPDF_DOCUMENT new_doc = FPDF_LoadCustomDocument(&file_access, nullptr);
+  ASSERT_NE(nullptr, new_doc);
+  EXPECT_EQ(1, FPDF_GetPageCount(new_doc));
+  FPDF_PAGE new_page = FPDF_LoadPage(new_doc, 0);
+  ASSERT_NE(nullptr, new_page);
+  FPDF_BITMAP new_bitmap = RenderPage(new_page);
+  CompareBitmap(new_bitmap, 612, 792, md5_2);
+  FPDFBitmap_Destroy(new_bitmap);
+  FPDF_ClosePage(new_page);
+  FPDF_CloseDocument(new_doc);
+}