summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Pena <npm@chromium.org>2017-02-27 10:41:41 -0500
committerChromium commit bot <commit-bot@chromium.org>2017-02-27 21:10:18 +0000
commitbe90aaea3977eadeee589cdda66c61d06d6535b0 (patch)
tree05e11fd59e26378b9b9760bb2614a5f09baaacc9
parent3f72fb4a3c983de00bae9c8437a1c09df9c9955b (diff)
downloadpdfium-be90aaea3977eadeee589cdda66c61d06d6535b0.tar.xz
Add public API for creating a Type1 font
Given a stream of data, we create a type1 font and fill up the required dictionary entries according to PDF spec 1.7. Table 5.8 describes Type 1 font dictionaries, and Table 5.19 describes font descriptors. BUG=pdfium:667 Change-Id: I571b09fb533467d77ed0104e613726387aec1f87 Reviewed-on: https://pdfium-review.googlesource.com/2835 Reviewed-by: dsinclair <dsinclair@chromium.org> Commit-Queue: Nicolás Peña <npm@chromium.org>
-rw-r--r--fpdfsdk/fpdfedit_embeddertest.cpp63
-rw-r--r--fpdfsdk/fpdfedittext.cpp98
-rw-r--r--fpdfsdk/fpdfview_c_api_test.c5
-rw-r--r--public/fpdf_edit.h12
4 files changed, 176 insertions, 2 deletions
diff --git a/fpdfsdk/fpdfedit_embeddertest.cpp b/fpdfsdk/fpdfedit_embeddertest.cpp
index f877617b49..53554a1822 100644
--- a/fpdfsdk/fpdfedit_embeddertest.cpp
+++ b/fpdfsdk/fpdfedit_embeddertest.cpp
@@ -5,8 +5,11 @@
#include <memory>
#include <string>
+#include "core/fpdfapi/font/cpdf_font.h"
#include "core/fpdfapi/page/cpdf_page.h"
+#include "core/fpdfapi/parser/cpdf_array.h"
#include "core/fpdfapi/parser/cpdf_dictionary.h"
+#include "core/fpdfapi/parser/cpdf_stream.h"
#include "core/fxcrt/fx_system.h"
#include "fpdfsdk/fsdk_define.h"
#include "public/fpdf_edit.h"
@@ -440,3 +443,63 @@ TEST_F(FPDFEditEmbeddertest, DoubleGenerating) {
FPDF_ClosePage(page);
FPDF_CloseDocument(doc);
}
+
+TEST_F(FPDFEditEmbeddertest, Type1Font) {
+ // Create a new document
+ FPDF_DOCUMENT doc = FPDF_CreateNewDocument();
+ CPDF_Document* document = reinterpret_cast<CPDF_Document*>(doc);
+
+ // Get Times New Roman Bold as a Type 1 font
+ CPDF_Font* times_bold = CPDF_Font::GetStockFont(document, "Times-Bold");
+ uint8_t* data = times_bold->m_Font.GetFontData();
+ uint32_t size = times_bold->m_Font.GetSize();
+ FPDF_FONT font = FPDFText_LoadType1Font(doc, data, size);
+ ASSERT_TRUE(font);
+ CPDF_Font* type1_font = reinterpret_cast<CPDF_Font*>(font);
+ EXPECT_TRUE(type1_font->IsType1Font());
+
+ // Check that the font dictionary has the required keys according to the spec
+ CPDF_Dictionary* font_dict = type1_font->GetFontDict();
+ EXPECT_EQ("Font", font_dict->GetStringFor("Type"));
+ EXPECT_EQ("Type1", font_dict->GetStringFor("Subtype"));
+ EXPECT_EQ("Times New Roman Bold", font_dict->GetStringFor("BaseFont"));
+ ASSERT_TRUE(font_dict->KeyExist("FirstChar"));
+ ASSERT_TRUE(font_dict->KeyExist("LastChar"));
+ EXPECT_EQ(32, font_dict->GetIntegerFor("FirstChar"));
+ EXPECT_EQ(65532, font_dict->GetIntegerFor("LastChar"));
+ ASSERT_TRUE(font_dict->KeyExist("Widths"));
+ CPDF_Array* widths_array = font_dict->GetArrayFor("Widths");
+ EXPECT_EQ(65501U, widths_array->GetCount());
+ EXPECT_EQ(250, widths_array->GetNumberAt(0));
+ EXPECT_EQ(0, widths_array->GetNumberAt(8172));
+ EXPECT_EQ(1000, widths_array->GetNumberAt(65500));
+ ASSERT_TRUE(font_dict->KeyExist("FontDescriptor"));
+ CPDF_Dictionary* font_desc = font_dict->GetDictFor("FontDescriptor");
+ EXPECT_EQ("FontDescriptor", font_desc->GetStringFor("Type"));
+ EXPECT_EQ(font_dict->GetStringFor("BaseFont"),
+ font_desc->GetStringFor("FontName"));
+
+ // Check that the font descriptor has the required keys according to the spec
+ ASSERT_TRUE(font_desc->KeyExist("Flags"));
+ int font_flags = font_desc->GetIntegerFor("Flags");
+ EXPECT_TRUE(font_flags & FXFONT_BOLD);
+ EXPECT_TRUE(font_flags & FXFONT_NONSYMBOLIC);
+ ASSERT_TRUE(font_desc->KeyExist("FontBBox"));
+ EXPECT_EQ(4U, font_desc->GetArrayFor("FontBBox")->GetCount());
+ EXPECT_TRUE(font_desc->KeyExist("ItalicAngle"));
+ EXPECT_TRUE(font_desc->KeyExist("Ascent"));
+ EXPECT_TRUE(font_desc->KeyExist("Descent"));
+ EXPECT_TRUE(font_desc->KeyExist("CapHeight"));
+ EXPECT_TRUE(font_desc->KeyExist("StemV"));
+ ASSERT_TRUE(font_desc->KeyExist("FontFile"));
+
+ // Check that the font stream is the one that was provided
+ CPDF_Stream* font_stream = font_desc->GetStreamFor("FontFile");
+ ASSERT_EQ(size, font_stream->GetRawSize());
+ uint8_t* stream_data = font_stream->GetRawData();
+ for (size_t i = 0; i < size; i++)
+ EXPECT_EQ(data[i], stream_data[i]);
+
+ // Close document
+ FPDF_CloseDocument(doc);
+}
diff --git a/fpdfsdk/fpdfedittext.cpp b/fpdfsdk/fpdfedittext.cpp
index 79ca310f7c..8bf0a0ac46 100644
--- a/fpdfsdk/fpdfedittext.cpp
+++ b/fpdfsdk/fpdfedittext.cpp
@@ -2,12 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "public/fpdf_edit.h"
+#include <utility>
#include "core/fpdfapi/cpdf_modulemgr.h"
#include "core/fpdfapi/font/cpdf_font.h"
+#include "core/fpdfapi/font/cpdf_type1font.h"
#include "core/fpdfapi/page/cpdf_textobject.h"
+#include "core/fpdfapi/parser/cpdf_array.h"
+#include "core/fpdfapi/parser/cpdf_dictionary.h"
+#include "core/fpdfapi/parser/cpdf_document.h"
+#include "core/fpdfapi/parser/cpdf_name.h"
+#include "core/fpdfapi/parser/cpdf_number.h"
+#include "core/fpdfapi/parser/cpdf_reference.h"
+#include "core/fpdfapi/parser/cpdf_stream.h"
+#include "core/fxge/cfx_fontmgr.h"
+#include "core/fxge/fx_font.h"
#include "fpdfsdk/fsdk_define.h"
+#include "public/fpdf_edit.h"
DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPageObj_NewTextObj(FPDF_DOCUMENT document,
FPDF_BYTESTRING font,
@@ -35,4 +46,87 @@ DLLEXPORT FPDF_BOOL STDCALL FPDFText_SetText(FPDF_PAGEOBJECT text_object,
auto pTextObj = reinterpret_cast<CPDF_TextObject*>(text_object);
pTextObj->SetText(CFX_ByteString(text));
return true;
-} \ No newline at end of file
+}
+
+DLLEXPORT FPDF_FONT STDCALL FPDFText_LoadType1Font(FPDF_DOCUMENT document,
+ const uint8_t* data,
+ uint32_t size) {
+ CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
+ if (!pDoc || !data || size == 0)
+ return nullptr;
+
+ auto pFont = pdfium::MakeUnique<CFX_Font>();
+
+ // TODO(npm): Maybe use FT_Get_X11_Font_Format to check format?
+ if (!pFont->LoadEmbedded(data, size))
+ return nullptr;
+
+ CPDF_Dictionary* fontDict = pDoc->NewIndirect<CPDF_Dictionary>();
+ fontDict->SetNewFor<CPDF_Name>("Type", "Font");
+ fontDict->SetNewFor<CPDF_Name>("Subtype", "Type1");
+ CFX_ByteString name = pFont->GetFaceName();
+ if (name.IsEmpty())
+ name = "Unnamed";
+ fontDict->SetNewFor<CPDF_Name>("BaseFont", name);
+
+ uint32_t glyphIndex;
+ int currentChar = FXFT_Get_First_Char(pFont->GetFace(), &glyphIndex);
+ fontDict->SetNewFor<CPDF_Number>("FirstChar", currentChar);
+ int nextChar;
+ CPDF_Array* widthsArray = pDoc->NewIndirect<CPDF_Array>();
+ while (true) {
+ int width = pFont->GetGlyphWidth(glyphIndex);
+ widthsArray->AddNew<CPDF_Number>(width);
+ nextChar = FXFT_Get_Next_Char(pFont->GetFace(), currentChar, &glyphIndex);
+ if (glyphIndex == 0)
+ break;
+ for (int i = currentChar + 1; i < nextChar; i++)
+ widthsArray->AddNew<CPDF_Number>(0);
+ currentChar = nextChar;
+ }
+ fontDict->SetNewFor<CPDF_Number>("LastChar", currentChar);
+ fontDict->SetNewFor<CPDF_Reference>("Widths", pDoc, widthsArray->GetObjNum());
+ CPDF_Dictionary* fontDesc = pDoc->NewIndirect<CPDF_Dictionary>();
+ fontDesc->SetNewFor<CPDF_Name>("Type", "FontDescriptor");
+ fontDesc->SetNewFor<CPDF_Name>("FontName", name);
+ int flags = 0;
+ if (FXFT_Is_Face_fixedwidth(pFont->GetFace()))
+ flags |= FXFONT_FIXED_PITCH;
+ if (name.Find("Serif") > -1)
+ flags |= FXFONT_SERIF;
+ if (FXFT_Is_Face_Italic(pFont->GetFace()))
+ flags |= FXFONT_ITALIC;
+ if (FXFT_Is_Face_Bold(pFont->GetFace()))
+ flags |= FXFONT_BOLD;
+
+ // TODO(npm): How do I know if a Type1 font is symbolic, script, allcap,
+ // smallcap
+ flags |= FXFONT_NONSYMBOLIC;
+
+ fontDesc->SetNewFor<CPDF_Number>("Flags", flags);
+ FX_RECT bbox;
+ pFont->GetBBox(bbox);
+ auto pBBox = pdfium::MakeUnique<CPDF_Array>();
+ pBBox->AddNew<CPDF_Number>(bbox.left);
+ pBBox->AddNew<CPDF_Number>(bbox.bottom);
+ pBBox->AddNew<CPDF_Number>(bbox.right);
+ pBBox->AddNew<CPDF_Number>(bbox.top);
+ fontDesc->SetFor("FontBBox", std::move(pBBox));
+
+ // TODO(npm): calculate italic angle correctly
+ fontDesc->SetNewFor<CPDF_Number>("ItalicAngle", pFont->IsItalic() ? -12 : 0);
+
+ fontDesc->SetNewFor<CPDF_Number>("Ascent", pFont->GetAscent());
+ fontDesc->SetNewFor<CPDF_Number>("Descent", pFont->GetDescent());
+
+ // TODO(npm): calculate the capheight, stemV correctly
+ fontDesc->SetNewFor<CPDF_Number>("CapHeight", pFont->GetAscent());
+ fontDesc->SetNewFor<CPDF_Number>("StemV", pFont->IsBold() ? 120 : 70);
+
+ CPDF_Stream* pStream = pDoc->NewIndirect<CPDF_Stream>();
+ pStream->SetData(data, size);
+ fontDesc->SetNewFor<CPDF_Reference>("FontFile", pDoc, pStream->GetObjNum());
+ fontDict->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc,
+ fontDesc->GetObjNum());
+ return pDoc->LoadFont(fontDict);
+}
diff --git a/fpdfsdk/fpdfview_c_api_test.c b/fpdfsdk/fpdfview_c_api_test.c
index 8ec3a26d3a..54a33252b3 100644
--- a/fpdfsdk/fpdfview_c_api_test.c
+++ b/fpdfsdk/fpdfview_c_api_test.c
@@ -83,17 +83,22 @@ int CheckPDFiumCApi() {
CHK(FPDFPage_TransformAnnots);
CHK(FPDFPageObj_NewImgeObj);
CHK(FPDFImageObj_LoadJpegFile);
+ CHK(FPDFImageObj_LoadJpegFileInline);
CHK(FPDFImageObj_SetMatrix);
CHK(FPDFImageObj_SetBitmap);
CHK(FPDFPageObj_CreateNewPath);
CHK(FPDFPageObj_CreateNewRect);
CHK(FPDFPath_SetStrokeColor);
+ CHK(FPDFPath_SetStrokeWidth);
CHK(FPDFPath_SetFillColor);
CHK(FPDFPath_MoveTo);
CHK(FPDFPath_LineTo);
CHK(FPDFPath_BezierTo);
CHK(FPDFPath_Close);
CHK(FPDFPath_SetDrawMode);
+ CHK(FPDFPageObj_NewTextObj);
+ CHK(FPDFText_SetText);
+ CHK(FPDFText_LoadType1Font);
// fpdf_ext.h
CHK(FSDK_SetUnSpObjProcessHandler);
diff --git a/public/fpdf_edit.h b/public/fpdf_edit.h
index c8d7a44c8e..3350b5c6a7 100644
--- a/public/fpdf_edit.h
+++ b/public/fpdf_edit.h
@@ -406,6 +406,18 @@ DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPageObj_NewTextObj(FPDF_DOCUMENT document,
DLLEXPORT FPDF_BOOL STDCALL FPDFText_SetText(FPDF_PAGEOBJECT text_object,
FPDF_BYTESTRING text);
+// Returns a type 1 font object loaded from a stream of data. The font is loaded
+// into the document. The caller does not need to free the returned object.
+//
+// document - handle to the document.
+// data - the stream of data, which will be copied by the font object.
+// size - size of the stream, in bytes.
+//
+// Returns NULL on failure
+DLLEXPORT FPDF_FONT STDCALL FPDFText_LoadType1Font(FPDF_DOCUMENT document,
+ const uint8_t* data,
+ uint32_t size);
+
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus