diff options
author | Nicolas Pena <npm@chromium.org> | 2017-03-06 13:54:33 -0500 |
---|---|---|
committer | Chromium commit bot <commit-bot@chromium.org> | 2017-03-06 21:02:43 +0000 |
commit | d03ca4214e6db7123e1c2d0ea58e34f7cf67a568 (patch) | |
tree | 2f34c4d09095faddbb0e9951757bbadf6f2635f6 /fpdfsdk/fpdfedittext.cpp | |
parent | f6d0146200beec76f3d8676e22562d1acbc83d91 (diff) | |
download | pdfium-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.cpp | 277 |
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); +} |