FontInfo.cc 6.34 KB
Newer Older
1 2 3 4 5
//========================================================================
//
// FontInfo.cc
//
// Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
6
// Copyright (C) 2005-2008, 2010, 2017, 2018 Albert Astals Cid <aacid@kde.org>
7 8
// Copyright (C) 2005 Brad Hards <bradh@frogmouth.net>
// Copyright (C) 2006 Kouhei Sutou <kou@cozmixng.org>
9
// Copyright (C) 2009 Pino Toscano <pino@kde.org>
10
// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
Albert Astals Cid's avatar
Albert Astals Cid committed
11
// Copyright (C) 2010, 2012 Adrian Johnson <ajohnson@redneon.com>
Thomas Freitag's avatar
Thomas Freitag committed
12
// Copyright (C) 2010, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
Albert Astals Cid's avatar
Albert Astals Cid committed
13
// Copyright (C) 2011 Carlos Garcia Campos <carlosgc@gnome.org>
14
// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
15
// Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by the LiMux project of the city of Munich
16 17 18 19 20 21 22 23 24 25 26 27 28 29
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
//
//========================================================================

//========================================================================
//
// Based on code from pdffonts.cc
//
// Copyright 2001-2007 Glyph & Cog, LLC
//
//========================================================================

30
#include "config.h"
31 32 33 34 35 36 37 38 39 40 41 42 43 44
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <math.h>
#include "GlobalParams.h"
#include "Error.h"
#include "Object.h"
#include "Dict.h"
#include "GfxFont.h"
#include "Annot.h"
#include "PDFDoc.h"
#include "FontInfo.h"

45
FontInfoScanner::FontInfoScanner(PDFDoc *docA, int firstPage) {
46
  doc = docA;
47
  currentPage = firstPage + 1;
48 49 50 51 52 53 54 55 56 57
}

FontInfoScanner::~FontInfoScanner() {
}

GooList *FontInfoScanner::scan(int nPages) {
  GooList *result;
  Page *page;
  Dict *resDict;
  Annots *annots;
58
  int lastPage;
59 60

  if (currentPage > doc->getNumPages()) {
61
    return nullptr;
62 63 64 65 66
  }
 
  result = new GooList();

  lastPage = currentPage + nPages;
67 68
  if (lastPage > doc->getNumPages() + 1) {
    lastPage = doc->getNumPages() + 1;
69 70
  }

Thomas Freitag's avatar
Thomas Freitag committed
71
  XRef *xrefA = doc->getXRef()->copy();
72
  for (int pg = currentPage; pg < lastPage; ++pg) {
Hib Eris's avatar
Hib Eris committed
73 74 75
    page = doc->getPage(pg);
    if (!page) continue;

76
    if ((resDict = page->getResourceDictCopy(xrefA))) {
Thomas Freitag's avatar
Thomas Freitag committed
77 78
      scanFonts(xrefA, resDict, result);
      delete resDict;
79
    }
80
    annots = page->getAnnots();
81
    for (int i = 0; i < annots->getNumAnnots(); ++i) {
Albert Astals Cid's avatar
Albert Astals Cid committed
82 83
      Object obj1 = annots->getAnnot(i)->getAppearanceResDict();
      if (obj1.isDict()) {
Thomas Freitag's avatar
Thomas Freitag committed
84
        scanFonts(xrefA, obj1.getDict(), result);
85 86 87 88
      }
    }
  }

89
  currentPage = lastPage;
90

Thomas Freitag's avatar
Thomas Freitag committed
91
  delete xrefA;
92 93 94
  return result;
}

Thomas Freitag's avatar
Thomas Freitag committed
95
void FontInfoScanner::scanFonts(XRef *xrefA, Dict *resDict, GooList *fontsList) {
96 97 98 99
  GfxFontDict *gfxFontDict;
  GfxFont *font;

  // scan the fonts in this resource dictionary
100
  gfxFontDict = nullptr;
Albert Astals Cid's avatar
Albert Astals Cid committed
101
  Object obj1 = resDict->lookupNF("Font");
102
  if (obj1.isRef()) {
Albert Astals Cid's avatar
Albert Astals Cid committed
103
    Object obj2 = obj1.fetch(xrefA);
104
    if (obj2.isDict()) {
105
      Ref r = obj1.getRef();
Thomas Freitag's avatar
Thomas Freitag committed
106
      gfxFontDict = new GfxFontDict(xrefA, &r, obj2.getDict());
107 108
    }
  } else if (obj1.isDict()) {
109
    gfxFontDict = new GfxFontDict(xrefA, nullptr, obj1.getDict());
110 111
  }
  if (gfxFontDict) {
Albert Astals Cid's avatar
Albert Astals Cid committed
112
    for (int i = 0; i < gfxFontDict->getNumFonts(); ++i) {
113 114 115
      if ((font = gfxFontDict->getFont(i))) {
        Ref fontRef = *font->getID();

116 117
        // add this font to the list if not already found
        if (fonts.find(fontRef.num) == fonts.end()) {
Thomas Freitag's avatar
Thomas Freitag committed
118
          fontsList->append(new FontInfo(font, xrefA));
119
          fonts.insert(fontRef.num);
120 121 122 123 124 125 126 127
        }
      }
    }
    delete gfxFontDict;
  }

  // recursively scan any resource dictionaries in objects in this
  // resource dictionary
128
  const char *resTypes[] = { "XObject", "Pattern" };
Thomas Freitag's avatar
Thomas Freitag committed
129
  for (Guint resType = 0; resType < sizeof(resTypes) / sizeof(resTypes[0]); ++resType) {
Albert Astals Cid's avatar
Albert Astals Cid committed
130
    Object objDict = resDict->lookup(resTypes[resType]);
131
    if (objDict.isDict()) {
Albert Astals Cid's avatar
Albert Astals Cid committed
132 133
      for (int i = 0; i < objDict.dictGetLength(); ++i) {
        obj1 = objDict.dictGetValNF(i);
134
        if (obj1.isRef()) {
135
          // check for an already-seen object
136
          const Ref r = obj1.getRef();
137
          if (visitedObjects.find(r.num) != visitedObjects.end()) {
138 139 140
            continue;
          }

141
          visitedObjects.insert(r.num);
142 143
        }

Albert Astals Cid's avatar
Albert Astals Cid committed
144
        Object obj2 = obj1.fetch(xrefA);
145
        if (obj2.isStream()) {
Albert Astals Cid's avatar
Albert Astals Cid committed
146
          Object resObj = obj2.streamGetDict()->lookup("Resources");
147
          if (resObj.isDict() && resObj.getDict() != resDict) {
Thomas Freitag's avatar
Thomas Freitag committed
148
            scanFonts(xrefA, resObj.getDict(), fontsList);
149
          }
150
        }
151 152 153 154 155
      }
    }
  }
}

Thomas Freitag's avatar
Thomas Freitag committed
156
FontInfo::FontInfo(GfxFont *font, XRef *xref) {
157
  const GooString *origName;
158 159 160 161

  fontRef = *font->getID();

  // font name
162
  origName = font->getName();
163
  if (origName != nullptr) {
164
    name = font->getName()->copy();
165
  } else {
166
    name = nullptr;
167
  }
168

169
  // font type
170
  type = (FontInfo::Type)font->getType();
171 172 173 174 175 176 177 178

  // check for an embedded font
  if (font->getType() == fontType3) {
    emb = gTrue;
  } else {
    emb = font->getEmbeddedFontID(&embRef);
  }

179 180
  file = nullptr;
  substituteName = nullptr;
181 182
  if (!emb)
  {
183 184 185 186 187 188
    SysFontType dummy;
    int dummy2;
    GooString substituteNameAux;
    file = globalParams->findSystemFontFile(font, &dummy, &dummy2, &substituteNameAux);
    if (substituteNameAux.getLength() > 0)
	substituteName = substituteNameAux.copy();
189
  }
190
  encoding = font->getEncodingName()->copy();
191

192 193
  // look for a ToUnicode map
  hasToUnicode = gFalse;
Albert Astals Cid's avatar
Albert Astals Cid committed
194 195 196
  Object fontObj = xref->fetch(fontRef.num, fontRef.gen);
  if (fontObj.isDict()) {
    hasToUnicode = fontObj.dictLookup("ToUnicode").isStream();
197 198 199 200 201 202
  }

  // check for a font subset name: capital letters followed by a '+'
  // sign
  subset = gFalse;
  if (name) {
Albert Astals Cid's avatar
Albert Astals Cid committed
203
    int i;
204 205 206 207 208 209 210 211 212 213
    for (i = 0; i < name->getLength(); ++i) {
      if (name->getChar(i) < 'A' || name->getChar(i) > 'Z') {
	break;
      }
    }
    subset = i > 0 && i < name->getLength() && name->getChar(i) == '+';
  }
}

FontInfo::FontInfo(FontInfo& f) {
214 215 216 217
  name = f.name ? f.name->copy() : nullptr;
  file = f.file ? f.file->copy() : nullptr;
  encoding = f.encoding ? f.encoding->copy() : nullptr;
  substituteName = f.substituteName ? f.substituteName->copy() : nullptr;
218
  type = f.type;
219 220 221 222
  emb = f.emb;
  subset = f.subset;
  hasToUnicode = f.hasToUnicode;
  fontRef = f.fontRef;
223
  embRef = f.embRef;
224 225 226 227
}

FontInfo::~FontInfo() {
  delete name;
228
  delete file;
229
  delete encoding;
230 231
  if (substituteName)
    delete substituteName;
232
}