Home | History | Annotate | Download | only in fpdfsdk
      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 
     23 DLLEXPORT 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 
     41 DLLEXPORT 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 
     51 DLLEXPORT 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