Commit 4ef85bc8 authored by Tobias Deiminger's avatar Tobias Deiminger

Ask freetype for font metrics

Font metrics from PDF font dictionary or builtin tables are only true
for one defined font. If that font is not available but gets subsituted,
we need other metrics. Else text looks ugly. The most honest source for
system font metrics is FreeType, so use it.
parent c4c55d9e
Pipeline #5220 passed with stage
in 4 minutes and 34 seconds
......@@ -46,6 +46,7 @@
#pragma implementation
#endif
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
......@@ -70,6 +71,9 @@
#include "GfxFont.h"
#include "PSOutputDev.h"
#include <ft2build.h>
#include FT_FREETYPE_H
//------------------------------------------------------------------------
struct Base14FontMapEntry {
......@@ -945,6 +949,101 @@ static GBool testForNumericNames(Dict *fontDict, GBool hex) {
return numeric;
}
std::vector<double> Gfx8BitFont::getFontMetricsFromFreeType(XRef *xref) {
GooString *fileName = nullptr;
std::unique_ptr<FoFiTrueType> ff;
char *tmpBuf = nullptr;
int tmpBufLen = 0;
// Didn't this happen before?
std::unique_ptr<GfxFontLoc> fontLoc(locateFont(xref, nullptr));
if (!fontLoc) {
error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'",
getName() ? getName()->getCString() : "(unnamed)");
return {};
}
// embedded font
if (fontLoc->locType == gfxFontLocEmbedded) {
// TD: if we have an embedded font, everything's perfect, we don't need to gather metrics manually at all?
tmpBuf = readEmbFontFile(xref, &tmpBufLen);
ff.reset(FoFiTrueType::make(tmpBuf, tmpBufLen));
if (! tmpBuf) {
return {};
}
// external font
} else { // gfxFontLocExternal
fileName = fontLoc->path;
ff.reset(FoFiTrueType::load(fileName->getCString()));
std::cout << "filename is " << fileName->getCString() << std::endl;
}
// Set up FreeType library TODO: Error handling
FT_Library ftLibrary;
auto error = FT_Init_FreeType( &ftLibrary );
FT_Face ftFace;
// TODO: Is 0 always the correct choice here?
int faceIndex = 0; // Get the zero-th face, in case the font source contains more than one
if (fileName) {
if (FT_New_Face(ftLibrary, fileName->getCString(), faceIndex, &ftFace))
std::cout << "FT_New_Face returned error code!" << std::endl;
} else {
if (FT_New_Memory_Face(ftLibrary, (const FT_Byte *)tmpBuf, tmpBufLen, faceIndex, &ftFace))
std::cout << "FT_New_Memory_Face returned error code!" << std::endl;
}
std::cout << "FreeType font family name: " << ftFace->family_name << std::endl;
std::cout << " ... number of glyphs: " << ftFace->num_glyphs << std::endl;
// TODO: Set this to something reasonable
// TODO: Error handling
error = FT_Set_Char_Size(
ftFace, /* handle to face object */
0, /* char_width in 1/64th of points, 0 means: same as height */
16*64, /* char_height in 1/64th of points */
200, /* horizontal device resolution */
200 ); /* vertical device resolution */
std::vector<double> freeTypeWidths(256);
int* codeToGID = getCodeToGIDMap(ff.get());
for (int c=0; c<256; c++) {
FT_UInt gid;
/*
* SplashFTFont::makeGlyph is doing something similar
Type1 fonts: map from name to gid, use FT_Get_Name_Index
CID fonts: see getCIDToGID
// if we're substituting for a non-TrueType font, we need to mark
// all notdef codes as "do not draw" (rather than drawing TrueType
// notdef glyphs)
if (ff->codeToGID && c < ff->codeToGIDLen && c >= 0) {
gid = (FT_UInt)ff->codeToGID[c];
} else { */
//gid = (FT_UInt)c;
gid = codeToGID[c];
/* } */
error = FT_Load_Glyph(ftFace,
gid, // glyph_index: The index of the glyph in the font file. For CID-keyed fonts (either in PS or in CFF format) this argument specifies the CID value.
FT_LOAD_NO_SCALE); // Load flags, TODO: 0 may not be the best choice
//std::cout << "FT error: " << error << std::endl;
freeTypeWidths[c] = (double)(ftFace->glyph->metrics.horiAdvance) / (double)ftFace->units_per_EM; //* 0.001;
}
FT_Done_Face(ftFace);
FT_Done_FreeType(ftLibrary);
return freeTypeWidths;
}
Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA,
GfxFontType typeA, Ref embFontIDA, Dict *fontDict):
GfxFont(tagA, idA, nameA, typeA, embFontIDA) {
......@@ -1376,6 +1475,14 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, const char *tagA, Ref idA, GooString *nameA
// couldn't find widths -- use defaults
} else {
auto freeTypeWidths = getFontMetricsFromFreeType(xref);
std::copy(freeTypeWidths.begin(), freeTypeWidths.end(), widths);
ok = true;
return;
// this is technically an error -- the Widths entry is required
// for all but the Base-14 fonts -- but certain PDF generators
// apparently don't include widths for Arial and TimesNewRoman
......
......@@ -369,6 +369,8 @@ public:
private:
~Gfx8BitFont();
std::vector<double> getFontMetricsFromFreeType(XRef *xref);
const Base14FontMapEntry *base14; // for Base-14 fonts only; NULL otherwise
char *enc[256]; // char code --> char name
char encFree[256]; // boolean for each char name: if set,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment