summaryrefslogtreecommitdiff
path: root/fpdfsdk/fpdfedittext.cpp
diff options
context:
space:
mode:
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);
+}