summaryrefslogtreecommitdiff
path: root/fpdfsdk/fpdfedittext.cpp
diff options
context:
space:
mode:
authorNicolas Pena <npm@chromium.org>2017-03-06 13:54:33 -0500
committerChromium commit bot <commit-bot@chromium.org>2017-03-06 21:02:43 +0000
commitd03ca4214e6db7123e1c2d0ea58e34f7cf67a568 (patch)
tree2f34c4d09095faddbb0e9951757bbadf6f2635f6 /fpdfsdk/fpdfedittext.cpp
parentf6d0146200beec76f3d8676e22562d1acbc83d91 (diff)
downloadpdfium-d03ca4214e6db7123e1c2d0ea58e34f7cf67a568.tar.xz
Add public method FPDFText_LoadFont to load some types of fonts.
The new method replaces the previous one for loading only type1 fonts. This will create the font dictionary with the very basics needed, according to the tables in chapter 5 of the PDF spec. The tests for now are only checking that the information is getting passed on properly. Followup: adding text with those fonts, generating the contents (doing that will allow testing whether the parts that I've skipped like Encoding and cmaps are needed or not). BUG=pdfium:667 Change-Id: Id1a61501e09542804a391552fd002f2caed41939 Reviewed-on: https://pdfium-review.googlesource.com/2915 Commit-Queue: Nicolás Peña <npm@chromium.org> Reviewed-by: Tom Sepez <tsepez@chromium.org>
Diffstat (limited to 'fpdfsdk/fpdfedittext.cpp')
-rw-r--r--fpdfsdk/fpdfedittext.cpp277
1 files changed, 207 insertions, 70 deletions
diff --git a/fpdfsdk/fpdfedittext.cpp b/fpdfsdk/fpdfedittext.cpp
index 8bf0a0ac46..5ce4be65a1 100644
--- a/fpdfsdk/fpdfedittext.cpp
+++ b/fpdfsdk/fpdfedittext.cpp
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <memory>
#include <utility>
#include "core/fpdfapi/cpdf_modulemgr.h"
@@ -20,87 +21,28 @@
#include "fpdfsdk/fsdk_define.h"
#include "public/fpdf_edit.h"
-DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPageObj_NewTextObj(FPDF_DOCUMENT document,
- FPDF_BYTESTRING font,
- float font_size) {
- CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
- if (!pDoc)
- return nullptr;
-
- CPDF_Font* pFont = CPDF_Font::GetStockFont(pDoc, CFX_ByteStringC(font));
- if (!pFont)
- return nullptr;
+namespace {
- CPDF_TextObject* pTextObj = new CPDF_TextObject;
- pTextObj->m_TextState.SetFont(pFont);
- pTextObj->m_TextState.SetFontSize(font_size);
- pTextObj->DefaultStates();
- return pTextObj;
-}
-
-DLLEXPORT FPDF_BOOL STDCALL FPDFText_SetText(FPDF_PAGEOBJECT text_object,
- FPDF_BYTESTRING text) {
- if (!text_object)
- return false;
-
- auto pTextObj = reinterpret_cast<CPDF_TextObject*>(text_object);
- pTextObj->SetText(CFX_ByteString(text));
- return true;
-}
-
-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* LoadFontDesc(CPDF_Document* pDoc,
+ const CFX_ByteString& font_name,
+ CFX_Font* pFont,
+ const uint8_t* data,
+ uint32_t size,
+ int font_type) {
CPDF_Dictionary* fontDesc = pDoc->NewIndirect<CPDF_Dictionary>();
fontDesc->SetNewFor<CPDF_Name>("Type", "FontDescriptor");
- fontDesc->SetNewFor<CPDF_Name>("FontName", name);
+ fontDesc->SetNewFor<CPDF_Name>("FontName", font_name);
int flags = 0;
if (FXFT_Is_Face_fixedwidth(pFont->GetFace()))
flags |= FXFONT_FIXED_PITCH;
- if (name.Find("Serif") > -1)
+ if (font_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
+ // TODO(npm): How do I know if a font is symbolic, script, allcap, smallcap
flags |= FXFONT_NONSYMBOLIC;
fontDesc->SetNewFor<CPDF_Number>("Flags", flags);
@@ -125,8 +67,203 @@ DLLEXPORT FPDF_FONT STDCALL FPDFText_LoadType1Font(FPDF_DOCUMENT document,
CPDF_Stream* pStream = pDoc->NewIndirect<CPDF_Stream>();
pStream->SetData(data, size);
- fontDesc->SetNewFor<CPDF_Reference>("FontFile", pDoc, pStream->GetObjNum());
+ CFX_ByteString fontFile =
+ font_type == FPDF_FONT_TYPE1 ? "FontFile" : "FontFile2";
+ fontDesc->SetNewFor<CPDF_Reference>(fontFile, pDoc, pStream->GetObjNum());
+ return fontDesc;
+}
+
+void* LoadSimpleFont(CPDF_Document* pDoc,
+ std::unique_ptr<CFX_Font> pFont,
+ const uint8_t* data,
+ uint32_t size,
+ int font_type) {
+ CPDF_Dictionary* fontDict = pDoc->NewIndirect<CPDF_Dictionary>();
+ fontDict->SetNewFor<CPDF_Name>("Type", "Font");
+ fontDict->SetNewFor<CPDF_Name>(
+ "Subtype", font_type == FPDF_FONT_TYPE1 ? "Type1" : "TrueType");
+ 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);
+ CPDF_Array* widthsArray = pDoc->NewIndirect<CPDF_Array>();
+ while (true) {
+ int width = pFont->GetGlyphWidth(glyphIndex);
+ widthsArray->AddNew<CPDF_Number>(width);
+ int nextChar =
+ FXFT_Get_Next_Char(pFont->GetFace(), currentChar, &glyphIndex);
+ // Simple fonts have 1-byte charcodes only.
+ if (nextChar > 0xff || 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 =
+ LoadFontDesc(pDoc, name, pFont.get(), data, size, font_type);
+
fontDict->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc,
fontDesc->GetObjNum());
return pDoc->LoadFont(fontDict);
}
+
+void* LoadCompositeFont(CPDF_Document* pDoc,
+ std::unique_ptr<CFX_Font> pFont,
+ const uint8_t* data,
+ uint32_t size,
+ int font_type) {
+ CPDF_Dictionary* fontDict = pDoc->NewIndirect<CPDF_Dictionary>();
+ fontDict->SetNewFor<CPDF_Name>("Type", "Font");
+ fontDict->SetNewFor<CPDF_Name>("Subtype", "Type0");
+ // TODO(npm): Get the correct encoding, if it's not identity.
+ CFX_ByteString encoding = "Identity-H";
+ fontDict->SetNewFor<CPDF_Name>("Encoding", encoding);
+ CFX_ByteString name = pFont->GetFaceName();
+ if (name.IsEmpty())
+ name = "Unnamed";
+ fontDict->SetNewFor<CPDF_Name>(
+ "BaseFont", font_type == FPDF_FONT_TYPE1 ? name + "-" + encoding : name);
+
+ CPDF_Dictionary* pCIDFont = pDoc->NewIndirect<CPDF_Dictionary>();
+ pCIDFont->SetNewFor<CPDF_Name>("Type", "Font");
+ pCIDFont->SetNewFor<CPDF_Name>("Subtype", font_type == FPDF_FONT_TYPE1
+ ? "CIDFontType0"
+ : "CIDFontType2");
+ pCIDFont->SetNewFor<CPDF_Name>("BaseFont", name);
+
+ // TODO(npm): Maybe use FT_Get_CID_Registry_Ordering_Supplement to get the
+ // CIDSystemInfo
+ CPDF_Dictionary* pCIDSystemInfo = pDoc->NewIndirect<CPDF_Dictionary>();
+ pCIDSystemInfo->SetNewFor<CPDF_Name>("Registry", "Adobe");
+ pCIDSystemInfo->SetNewFor<CPDF_Name>("Ordering", "Identity");
+ pCIDSystemInfo->SetNewFor<CPDF_Number>("Supplement", 0);
+ pCIDFont->SetNewFor<CPDF_Reference>("CIDSystemInfo", pDoc,
+ pCIDSystemInfo->GetObjNum());
+
+ CPDF_Dictionary* fontDesc =
+ LoadFontDesc(pDoc, name, pFont.get(), data, size, font_type);
+ pCIDFont->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc,
+ fontDesc->GetObjNum());
+
+ uint32_t glyphIndex;
+ int currentChar = FXFT_Get_First_Char(pFont->GetFace(), &glyphIndex);
+ CPDF_Array* widthsArray = pDoc->NewIndirect<CPDF_Array>();
+ while (true) {
+ int width = pFont->GetGlyphWidth(glyphIndex);
+ int nextChar =
+ FXFT_Get_Next_Char(pFont->GetFace(), currentChar, &glyphIndex);
+ if (glyphIndex == 0) {
+ // Only one char left, use format c [w]
+ auto oneW = pdfium::MakeUnique<CPDF_Array>();
+ oneW->AddNew<CPDF_Number>(width);
+ widthsArray->AddNew<CPDF_Number>(currentChar);
+ widthsArray->Add(std::move(oneW));
+ break;
+ }
+ int nextWidth = pFont->GetGlyphWidth(glyphIndex);
+ if (nextChar == currentChar + 1 && nextWidth == width) {
+ // The array can have a group c_first c_last w: all CIDs in the range from
+ // c_first to c_last will have width w
+ widthsArray->AddNew<CPDF_Number>(currentChar);
+ currentChar = nextChar;
+ while (true) {
+ nextChar =
+ FXFT_Get_Next_Char(pFont->GetFace(), currentChar, &glyphIndex);
+ if (glyphIndex == 0)
+ break;
+ nextWidth = pFont->GetGlyphWidth(glyphIndex);
+ if (nextChar != currentChar + 1 || nextWidth != width)
+ break;
+ currentChar = nextChar;
+ }
+ widthsArray->AddNew<CPDF_Number>(currentChar);
+ widthsArray->AddNew<CPDF_Number>(width);
+ } else {
+ // Otherwise we can have a group of the form c [w1 w2 ...]: c has width
+ // w1, c+1 has width w2, etc.
+ widthsArray->AddNew<CPDF_Number>(currentChar);
+ auto curWidthArray = pdfium::MakeUnique<CPDF_Array>();
+ curWidthArray->AddNew<CPDF_Number>(width);
+ while (nextChar == currentChar + 1) {
+ curWidthArray->AddNew<CPDF_Number>(nextWidth);
+ currentChar = nextChar;
+ nextChar =
+ FXFT_Get_Next_Char(pFont->GetFace(), currentChar, &glyphIndex);
+ if (glyphIndex == 0)
+ break;
+ nextWidth = pFont->GetGlyphWidth(glyphIndex);
+ }
+ widthsArray->Add(std::move(curWidthArray));
+ }
+ if (glyphIndex == 0)
+ break;
+ currentChar = nextChar;
+ }
+ pCIDFont->SetNewFor<CPDF_Reference>("W", pDoc, widthsArray->GetObjNum());
+ // TODO(npm): Support vertical writing
+
+ auto pDescendant = pdfium::MakeUnique<CPDF_Array>();
+ pDescendant->AddNew<CPDF_Reference>(pDoc, pCIDFont->GetObjNum());
+ fontDict->SetFor("DescendantFonts", std::move(pDescendant));
+ // TODO(npm): do we need a ToUnicode?
+ return pDoc->LoadFont(fontDict);
+}
+
+} // namespace
+
+DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPageObj_NewTextObj(FPDF_DOCUMENT document,
+ FPDF_BYTESTRING font,
+ float font_size) {
+ CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
+ if (!pDoc)
+ return nullptr;
+
+ CPDF_Font* pFont = CPDF_Font::GetStockFont(pDoc, CFX_ByteStringC(font));
+ if (!pFont)
+ return nullptr;
+
+ CPDF_TextObject* pTextObj = new CPDF_TextObject;
+ pTextObj->m_TextState.SetFont(pFont);
+ pTextObj->m_TextState.SetFontSize(font_size);
+ pTextObj->DefaultStates();
+ return pTextObj;
+}
+
+DLLEXPORT FPDF_BOOL STDCALL FPDFText_SetText(FPDF_PAGEOBJECT text_object,
+ FPDF_BYTESTRING text) {
+ if (!text_object)
+ return false;
+
+ auto pTextObj = reinterpret_cast<CPDF_TextObject*>(text_object);
+ pTextObj->SetText(CFX_ByteString(text));
+ return true;
+}
+
+DLLEXPORT FPDF_FONT STDCALL FPDFText_LoadFont(FPDF_DOCUMENT document,
+ const uint8_t* data,
+ uint32_t size,
+ int font_type,
+ FPDF_BOOL cid) {
+ CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
+ if (!pDoc || !data || size == 0 ||
+ (font_type != FPDF_FONT_TYPE1 && font_type != FPDF_FONT_TRUETYPE)) {
+ return nullptr;
+ }
+
+ auto pFont = pdfium::MakeUnique<CFX_Font>();
+
+ // TODO(npm): Maybe use FT_Get_X11_Font_Format to check format? Otherwise, we
+ // are allowing giving any font that can be loaded on freetype and setting it
+ // as any font type.
+ if (!pFont->LoadEmbedded(data, size))
+ return nullptr;
+
+ return cid ? LoadCompositeFont(pDoc, std::move(pFont), data, size, font_type)
+ : LoadSimpleFont(pDoc, std::move(pFont), data, size, font_type);
+}