blob: bd2fa82fce720b8a5ca0a6750bc89f17eef97616 [file] [log] [blame]
// Copyright 2016 The PDFium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#include "core/fpdfapi/font/cpdf_simplefont.h"
#include <algorithm>
#include <array>
#include <iterator>
#include <utility>
#include "constants/font_encodings.h"
#include "core/fpdfapi/parser/cpdf_array.h"
#include "core/fpdfapi/parser/cpdf_dictionary.h"
#include "core/fpdfapi/parser/cpdf_name.h"
#include "core/fxcrt/fx_codepage.h"
#include "core/fxge/freetype/fx_freetype.h"
#include "core/fxge/fx_font.h"
namespace {
void GetPredefinedEncoding(const ByteString& value, FontEncoding* basemap) {
if (value == pdfium::font_encodings::kWinAnsiEncoding) {
*basemap = FontEncoding::kWinAnsi;
} else if (value == pdfium::font_encodings::kMacRomanEncoding) {
*basemap = FontEncoding::kMacRoman;
} else if (value == pdfium::font_encodings::kMacExpertEncoding) {
*basemap = FontEncoding::kMacExpert;
} else if (value == pdfium::font_encodings::kPDFDocEncoding) {
*basemap = FontEncoding::kPdfDoc;
}
}
} // namespace
CPDF_SimpleFont::CPDF_SimpleFont(CPDF_Document* document,
RetainPtr<CPDF_Dictionary> font_dict)
: CPDF_Font(document, std::move(font_dict)) {
char_width_.fill(0xffff);
glyph_index_.fill(0xffff);
char_bbox_.fill(FX_RECT(-1, -1, -1, -1));
}
CPDF_SimpleFont::~CPDF_SimpleFont() = default;
int CPDF_SimpleFont::GlyphFromCharCode(uint32_t charcode, bool* pVertGlyph) {
if (pVertGlyph) {
*pVertGlyph = false;
}
if (charcode > 0xff) {
return -1;
}
int index = glyph_index_[charcode];
if (index == 0xffff) {
return -1;
}
return index;
}
void CPDF_SimpleFont::LoadCharMetrics(int charcode) {
if (!font_.HasFaceRec()) {
return;
}
if (charcode < 0 || charcode > 0xff) {
return;
}
int glyph_index = glyph_index_[charcode];
if (glyph_index == 0xffff) {
if (!font_file_ && charcode != 32) {
LoadCharMetrics(32);
char_bbox_[charcode] = char_bbox_[32];
if (use_font_width_) {
char_width_[charcode] = char_width_[32];
}
}
return;
}
RetainPtr<CFX_Face> face = font_.GetFace();
if (!face) {
return;
}
FXFT_FaceRec* face_rec = face->GetRec();
int err =
FT_Load_Glyph(face_rec, glyph_index,
FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
if (err) {
return;
}
char_bbox_[charcode] = face->GetGlyphBBox();
if (use_font_width_) {
int TT_Width = NormalizeFontMetric(FXFT_Get_Glyph_HoriAdvance(face_rec),
face->GetUnitsPerEm());
if (char_width_[charcode] == 0xffff) {
char_width_[charcode] = TT_Width;
} else if (TT_Width && !IsEmbedded()) {
char_bbox_[charcode].right =
char_bbox_[charcode].right * char_width_[charcode] / TT_Width;
char_bbox_[charcode].left =
char_bbox_[charcode].left * char_width_[charcode] / TT_Width;
}
}
}
void CPDF_SimpleFont::LoadCharWidths(const CPDF_Dictionary* font_desc) {
RetainPtr<const CPDF_Array> width_array = font_dict_->GetArrayFor("Widths");
use_font_width_ = !width_array;
if (!width_array) {
return;
}
if (font_desc && font_desc->KeyExist("MissingWidth")) {
int missing_width = font_desc->GetIntegerFor("MissingWidth");
std::fill(std::begin(char_width_), std::end(char_width_), missing_width);
}
size_t width_start = font_dict_->GetIntegerFor("FirstChar", 0);
size_t width_end = font_dict_->GetIntegerFor("LastChar", 0);
if (width_start > 255) {
return;
}
if (width_end == 0 || width_end >= width_start + width_array->size()) {
width_end = width_start + width_array->size() - 1;
}
if (width_end > 255) {
width_end = 255;
}
for (size_t i = width_start; i <= width_end; i++) {
char_width_[i] = width_array->GetIntegerAt(i - width_start);
}
}
void CPDF_SimpleFont::LoadDifferences(const CPDF_Dictionary* encoding) {
RetainPtr<const CPDF_Array> diffs = encoding->GetArrayFor("Differences");
if (!diffs) {
return;
}
char_names_.resize(kInternalTableSize);
uint32_t cur_code = 0;
for (uint32_t i = 0; i < diffs->size(); i++) {
RetainPtr<const CPDF_Object> element = diffs->GetDirectObjectAt(i);
if (!element) {
continue;
}
const CPDF_Name* name = element->AsName();
if (name) {
if (cur_code < char_names_.size()) {
char_names_[cur_code] = name->GetString();
}
cur_code++;
} else {
cur_code = element->GetInteger();
}
}
}
void CPDF_SimpleFont::LoadPDFEncoding(bool bEmbedded, bool bTrueType) {
RetainPtr<const CPDF_Object> pEncoding =
font_dict_->GetDirectObjectFor("Encoding");
if (!pEncoding) {
if (base_font_name_ == "Symbol") {
base_encoding_ =
bTrueType ? FontEncoding::kMsSymbol : FontEncoding::kAdobeSymbol;
} else if (!bEmbedded && base_encoding_ == FontEncoding::kBuiltin) {
base_encoding_ = FontEncoding::kWinAnsi;
}
return;
}
if (pEncoding->IsName()) {
if (base_encoding_ == FontEncoding::kAdobeSymbol ||
base_encoding_ == FontEncoding::kZapfDingbats) {
return;
}
if (FontStyleIsSymbolic(flags_) && base_font_name_ == "Symbol") {
if (!bTrueType) {
base_encoding_ = FontEncoding::kAdobeSymbol;
}
return;
}
ByteString bsEncoding = pEncoding->GetString();
if (bsEncoding == pdfium::font_encodings::kMacExpertEncoding) {
bsEncoding = pdfium::font_encodings::kWinAnsiEncoding;
}
GetPredefinedEncoding(bsEncoding, &base_encoding_);
return;
}
const CPDF_Dictionary* dict = pEncoding->AsDictionary();
if (!dict) {
return;
}
if (base_encoding_ != FontEncoding::kAdobeSymbol &&
base_encoding_ != FontEncoding::kZapfDingbats) {
ByteString bsEncoding = dict->GetByteStringFor("BaseEncoding");
if (bTrueType && bsEncoding == pdfium::font_encodings::kMacExpertEncoding) {
bsEncoding = pdfium::font_encodings::kWinAnsiEncoding;
}
GetPredefinedEncoding(bsEncoding, &base_encoding_);
}
if ((!bEmbedded || bTrueType) && base_encoding_ == FontEncoding::kBuiltin) {
base_encoding_ = FontEncoding::kStandard;
}
LoadDifferences(dict);
}
int CPDF_SimpleFont::GetCharWidthF(uint32_t charcode) {
if (charcode > 0xff) {
charcode = 0;
}
if (char_width_[charcode] == 0xffff) {
LoadCharMetrics(charcode);
if (char_width_[charcode] == 0xffff) {
char_width_[charcode] = 0;
}
}
return char_width_[charcode];
}
FX_RECT CPDF_SimpleFont::GetCharBBox(uint32_t charcode) {
if (charcode > 0xff) {
charcode = 0;
}
if (char_bbox_[charcode].left == -1) {
LoadCharMetrics(charcode);
}
return char_bbox_[charcode];
}
bool CPDF_SimpleFont::LoadCommon() {
RetainPtr<const CPDF_Dictionary> font_desc =
font_dict_->GetDictFor("FontDescriptor");
if (font_desc) {
LoadFontDescriptor(font_desc.Get());
}
LoadCharWidths(font_desc.Get());
if (font_file_) {
if (base_font_name_.GetLength() > 7 && base_font_name_[6] == '+') {
base_font_name_ = base_font_name_.Last(base_font_name_.GetLength() - 7);
}
} else {
LoadSubstFont();
}
if (!FontStyleIsSymbolic(flags_)) {
base_encoding_ = FontEncoding::kStandard;
}
LoadPDFEncoding(!!font_file_, font_.IsTTFont());
LoadGlyphMap();
char_names_.clear();
if (!HasFace()) {
return true;
}
if (FontStyleIsAllCaps(flags_)) {
static const auto kLowercases =
std::to_array<std::pair<const uint8_t, const uint8_t>>(
{{'a', 'z'}, {0xe0, 0xf6}, {0xf8, 0xfd}});
for (const auto& lower : kLowercases) {
for (int i = lower.first; i <= lower.second; ++i) {
if (glyph_index_[i] != 0xffff && font_file_) {
continue;
}
int j = i - 32;
glyph_index_[i] = glyph_index_[j];
if (char_width_[j]) {
char_width_[i] = char_width_[j];
char_bbox_[i] = char_bbox_[j];
}
}
}
}
CheckFontMetrics();
return true;
}
void CPDF_SimpleFont::LoadSubstFont() {
if (!use_font_width_ && !FontStyleIsFixedPitch(flags_)) {
int width = 0;
size_t i;
for (i = 0; i < kInternalTableSize; i++) {
if (char_width_[i] == 0 || char_width_[i] == 0xffff) {
continue;
}
if (width == 0) {
width = char_width_[i];
} else if (width != char_width_[i]) {
break;
}
}
if (i == kInternalTableSize && width) {
flags_ |= pdfium::kFontStyleFixedPitch;
}
}
int weight = GetFontWeight().value_or(pdfium::kFontWeightNormal);
if (weight < pdfium::kFontWeightExtraLight ||
weight > pdfium::kFontWeightExtraBold) {
weight = pdfium::kFontWeightNormal;
}
font_.LoadSubst(base_font_name_, IsTrueTypeFont(), flags_, weight,
italic_angle_, FX_CodePage::kDefANSI, /*bVertical=*/false);
}
bool CPDF_SimpleFont::IsUnicodeCompatible() const {
return base_encoding_ != FontEncoding::kBuiltin &&
base_encoding_ != FontEncoding::kAdobeSymbol &&
base_encoding_ != FontEncoding::kZapfDingbats;
}
WideString CPDF_SimpleFont::UnicodeFromCharCode(uint32_t charcode) const {
WideString unicode = CPDF_Font::UnicodeFromCharCode(charcode);
if (!unicode.IsEmpty()) {
return unicode;
}
wchar_t ret = encoding_.UnicodeFromCharCode((uint8_t)charcode);
if (ret == 0) {
return WideString();
}
return WideString(ret);
}
uint32_t CPDF_SimpleFont::CharCodeFromUnicode(wchar_t unicode) const {
uint32_t ret = CPDF_Font::CharCodeFromUnicode(unicode);
if (ret) {
return ret;
}
return encoding_.CharCodeFromUnicode(unicode);
}
bool CPDF_SimpleFont::HasFontWidths() const {
return !use_font_width_;
}