fpdfedittext.cpp revision 5ae9d0c6fd838a2967cca72aa5751b51dadc2769
1// Copyright 2017 PDFium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <utility>
6
7#include "core/fpdfapi/cpdf_modulemgr.h"
8#include "core/fpdfapi/font/cpdf_font.h"
9#include "core/fpdfapi/font/cpdf_type1font.h"
10#include "core/fpdfapi/page/cpdf_textobject.h"
11#include "core/fpdfapi/parser/cpdf_array.h"
12#include "core/fpdfapi/parser/cpdf_dictionary.h"
13#include "core/fpdfapi/parser/cpdf_document.h"
14#include "core/fpdfapi/parser/cpdf_name.h"
15#include "core/fpdfapi/parser/cpdf_number.h"
16#include "core/fpdfapi/parser/cpdf_reference.h"
17#include "core/fpdfapi/parser/cpdf_stream.h"
18#include "core/fxge/cfx_fontmgr.h"
19#include "core/fxge/fx_font.h"
20#include "fpdfsdk/fsdk_define.h"
21#include "public/fpdf_edit.h"
22
23DLLEXPORT FPDF_PAGEOBJECT STDCALL FPDFPageObj_NewTextObj(FPDF_DOCUMENT document,
24                                                         FPDF_BYTESTRING font,
25                                                         float font_size) {
26  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
27  if (!pDoc)
28    return nullptr;
29
30  CPDF_Font* pFont = CPDF_Font::GetStockFont(pDoc, CFX_ByteStringC(font));
31  if (!pFont)
32    return nullptr;
33
34  CPDF_TextObject* pTextObj = new CPDF_TextObject;
35  pTextObj->m_TextState.SetFont(pFont);
36  pTextObj->m_TextState.SetFontSize(font_size);
37  pTextObj->DefaultStates();
38  return pTextObj;
39}
40
41DLLEXPORT FPDF_BOOL STDCALL FPDFText_SetText(FPDF_PAGEOBJECT text_object,
42                                             FPDF_BYTESTRING text) {
43  if (!text_object)
44    return false;
45
46  auto pTextObj = reinterpret_cast<CPDF_TextObject*>(text_object);
47  pTextObj->SetText(CFX_ByteString(text));
48  return true;
49}
50
51DLLEXPORT FPDF_FONT STDCALL FPDFText_LoadType1Font(FPDF_DOCUMENT document,
52                                                   const uint8_t* data,
53                                                   uint32_t size) {
54  CPDF_Document* pDoc = CPDFDocumentFromFPDFDocument(document);
55  if (!pDoc || !data || size == 0)
56    return nullptr;
57
58  auto pFont = pdfium::MakeUnique<CFX_Font>();
59
60  // TODO(npm): Maybe use FT_Get_X11_Font_Format to check format?
61  if (!pFont->LoadEmbedded(data, size))
62    return nullptr;
63
64  CPDF_Dictionary* fontDict = pDoc->NewIndirect<CPDF_Dictionary>();
65  fontDict->SetNewFor<CPDF_Name>("Type", "Font");
66  fontDict->SetNewFor<CPDF_Name>("Subtype", "Type1");
67  CFX_ByteString name = pFont->GetFaceName();
68  if (name.IsEmpty())
69    name = "Unnamed";
70  fontDict->SetNewFor<CPDF_Name>("BaseFont", name);
71
72  uint32_t glyphIndex;
73  int currentChar = FXFT_Get_First_Char(pFont->GetFace(), &glyphIndex);
74  fontDict->SetNewFor<CPDF_Number>("FirstChar", currentChar);
75  int nextChar;
76  CPDF_Array* widthsArray = pDoc->NewIndirect<CPDF_Array>();
77  while (true) {
78    int width = pFont->GetGlyphWidth(glyphIndex);
79    widthsArray->AddNew<CPDF_Number>(width);
80    nextChar = FXFT_Get_Next_Char(pFont->GetFace(), currentChar, &glyphIndex);
81    if (glyphIndex == 0)
82      break;
83    for (int i = currentChar + 1; i < nextChar; i++)
84      widthsArray->AddNew<CPDF_Number>(0);
85    currentChar = nextChar;
86  }
87  fontDict->SetNewFor<CPDF_Number>("LastChar", currentChar);
88  fontDict->SetNewFor<CPDF_Reference>("Widths", pDoc, widthsArray->GetObjNum());
89  CPDF_Dictionary* fontDesc = pDoc->NewIndirect<CPDF_Dictionary>();
90  fontDesc->SetNewFor<CPDF_Name>("Type", "FontDescriptor");
91  fontDesc->SetNewFor<CPDF_Name>("FontName", name);
92  int flags = 0;
93  if (FXFT_Is_Face_fixedwidth(pFont->GetFace()))
94    flags |= FXFONT_FIXED_PITCH;
95  if (name.Find("Serif") > -1)
96    flags |= FXFONT_SERIF;
97  if (FXFT_Is_Face_Italic(pFont->GetFace()))
98    flags |= FXFONT_ITALIC;
99  if (FXFT_Is_Face_Bold(pFont->GetFace()))
100    flags |= FXFONT_BOLD;
101
102  // TODO(npm): How do I know if a Type1 font is symbolic, script, allcap,
103  // smallcap
104  flags |= FXFONT_NONSYMBOLIC;
105
106  fontDesc->SetNewFor<CPDF_Number>("Flags", flags);
107  FX_RECT bbox;
108  pFont->GetBBox(bbox);
109  auto pBBox = pdfium::MakeUnique<CPDF_Array>();
110  pBBox->AddNew<CPDF_Number>(bbox.left);
111  pBBox->AddNew<CPDF_Number>(bbox.bottom);
112  pBBox->AddNew<CPDF_Number>(bbox.right);
113  pBBox->AddNew<CPDF_Number>(bbox.top);
114  fontDesc->SetFor("FontBBox", std::move(pBBox));
115
116  // TODO(npm): calculate italic angle correctly
117  fontDesc->SetNewFor<CPDF_Number>("ItalicAngle", pFont->IsItalic() ? -12 : 0);
118
119  fontDesc->SetNewFor<CPDF_Number>("Ascent", pFont->GetAscent());
120  fontDesc->SetNewFor<CPDF_Number>("Descent", pFont->GetDescent());
121
122  // TODO(npm): calculate the capheight, stemV correctly
123  fontDesc->SetNewFor<CPDF_Number>("CapHeight", pFont->GetAscent());
124  fontDesc->SetNewFor<CPDF_Number>("StemV", pFont->IsBold() ? 120 : 70);
125
126  CPDF_Stream* pStream = pDoc->NewIndirect<CPDF_Stream>();
127  pStream->SetData(data, size);
128  fontDesc->SetNewFor<CPDF_Reference>("FontFile", pDoc, pStream->GetObjNum());
129  fontDict->SetNewFor<CPDF_Reference>("FontDescriptor", pDoc,
130                                      fontDesc->GetObjNum());
131  return pDoc->LoadFont(fontDict);
132}
133