Commit a248a431 authored by Eddie Kohler's avatar Eddie Kohler

Attempt to handle CFF fonts with other than 1000 units per em.

Marc Penninga reported one.
parent 2ce88c69
/* cfftot1.cc -- driver for translating CFF fonts to Type 1 fonts
*
* Copyright (c) 2002-2013 Eddie Kohler
* Copyright (c) 2002-2014 Eddie Kohler
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
......@@ -143,10 +143,14 @@ do_file(const char *infn, const char *outfn, PermString name, ErrorHandler *errh
ContextErrorHandler cerrh(errh, "While processing %s:", infn);
cerrh.set_indent(0);
String data = sa.take_string();
if (c == 'O')
data = Efont::OpenType::Font(data, &cerrh).table("CFF");
unsigned units_per_em = 0;
if (c == 'O') {
Efont::OpenType::Font font(data, &cerrh);
data = font.table("CFF");
units_per_em = font.units_per_em();
}
Cff *cff = new Cff(data, &cerrh);
Cff *cff = new Cff(data, units_per_em, &cerrh);
Cff::FontParent *fp = cff->font(name, &cerrh);
if (errh->nerrors() == 0
&& !(font = dynamic_cast<Cff::Font *>(fp)))
......
......@@ -18,7 +18,8 @@ class Cff { public:
class CIDFont;
class ChildFont;
Cff(const String &, ErrorHandler * = 0);
explicit Cff(const String& str, unsigned units_per_em,
ErrorHandler* errh = 0);
~Cff();
bool ok() const { return _error >= 0; }
......@@ -41,6 +42,8 @@ class Cff { public:
int ngsubrs() const { return _gsubrs_index.nitems(); }
Charstring *gsubr(int i);
unsigned units_per_em() const { return _units_per_em; }
enum DictOperator {
oVersion = 0, oNotice = 1, oFullName = 2, oFamilyName = 3,
oWeight = 4, oFontBBox = 5, oBlueValues = 6, oOtherBlues = 7,
......@@ -80,8 +83,11 @@ class Cff { public:
int error() const { return (_offsize < 0 ? _offsize : 0); }
typedef bool (IndexIterator::*unspecified_bool_type)() const;
bool live() const { return _offset < _last_offset; }
operator bool() const { return live(); }
operator unspecified_bool_type() const {
return live() ? &IndexIterator::live : 0;
}
int nitems() const;
inline const uint8_t *operator*() const;
......@@ -121,6 +127,8 @@ class Cff { public:
IndexIterator _gsubrs_index;
Vector<Charstring *> _gsubrs_cs;
unsigned _units_per_em;
int parse_header(ErrorHandler *);
int font_offset(int, int &, int &) const;
int font_offset(PermString, int &, int &) const;
......@@ -215,7 +223,7 @@ class Cff::FDSelect { public:
class Cff::FontParent : public CharstringProgram { public:
FontParent(Cff *);
FontParent(Cff* cff);
bool ok() const { return _error >= 0; }
int error() const { return _error; }
......@@ -227,7 +235,7 @@ class Cff::FontParent : public CharstringProgram { public:
private:
Cff *_cff;
Cff* _cff;
int _charstring_type;
int _error;
......@@ -244,7 +252,7 @@ class Cff::FontParent : public CharstringProgram { public:
class Cff::CIDFont : public Cff::FontParent { public:
CIDFont(Cff *, PermString, const Dict &, ErrorHandler *);
CIDFont(Cff* cff, PermString, const Dict &, ErrorHandler *);
~CIDFont();
PermString font_name() const { return _font_name; }
......@@ -285,7 +293,7 @@ class Cff::CIDFont : public Cff::FontParent { public:
class Cff::ChildFont : public Cff::FontParent { public:
ChildFont(Cff *, Cff::CIDFont *, int charstring_type, const Dict &, ErrorHandler * = 0);
ChildFont(Cff* cff, Cff::CIDFont *, int charstring_type, const Dict &, ErrorHandler * = 0);
~ChildFont();
bool ok() const { return _error >= 0; }
......@@ -333,7 +341,7 @@ class Cff::ChildFont : public Cff::FontParent { public:
class Cff::Font : public Cff::ChildFont { public:
Font(Cff *, PermString, const Dict &, ErrorHandler *);
Font(Cff* cff, PermString, const Dict &, ErrorHandler *);
~Font();
PermString font_name() const { return _font_name; }
......
......@@ -18,8 +18,13 @@ class Tag {
Tag(const String &name);
// default destructor
static Tag head_tag() { return Tag(0x68656164U); }
typedef bool (Tag::*unspecified_bool_type)() const;
bool null() const { return _tag == 0; }
operator bool() const { return _tag != 0; }
operator unspecified_bool_type() const {
return _tag != 0 ? &Tag::null : 0;
}
bool valid() const;
uint32_t value() const { return _tag; }
......@@ -37,19 +42,25 @@ class Tag {
uint32_t _tag;
};
inline hashcode_t hashcode(const Tag& t) {
return t.value();
}
class Font {
public:
Font(const String&, ErrorHandler* = 0);
Font(const String& str, ErrorHandler* errh = 0);
// default destructor
bool ok() const { return _error >= 0; }
bool check_checksums(ErrorHandler * = 0) const;
bool check_checksums(ErrorHandler* errh = 0) const;
int error() const { return _error; }
const String& data_string() const { return _str; }
const uint8_t* data() const { return _str.udata(); }
int length() const { return _str.length(); }
unsigned units_per_em() const { return _units_per_em; }
int ntables() const;
bool has_table(Tag tag) const;
String table(Tag tag) const;
......@@ -65,6 +76,7 @@ class Font {
private:
String _str;
int _error;
unsigned _units_per_em;
int parse_header(ErrorHandler*);
};
......@@ -356,8 +368,4 @@ inline bool GlyphSet::operator[](Glyph g) const {
} // namespace Efont::OpenType
} // namespace Efont
inline hashcode_t hashcode(Efont::OpenType::Tag t) {
return t.value();
}
#endif
......@@ -67,7 +67,7 @@ class Data {
operator const String&() const { return _str; }
operator bool() const { return _str; }
operator String::unspecified_bool_type() const { return _str; }
const uint8_t *udata() const { return _str.udata(); }
int length() const { return _str.length(); }
......
......@@ -30,11 +30,13 @@ class CharstringBounds : public CharstringInterp { public:
void clear();
bool char_bounds(const CharstringContext&, bool shift = true);
void translate(double dx, double dy);
inline Point transform(const Point &) const;
bool output(int bb[4], int& width, bool use_cur_width = false) const;
inline Point transform(const Point& p) const;
bool output(double bb[4], double& width, bool use_cur_width = false) const;
static bool bounds(const CharstringContext&, int bounds[4], int& width);
static bool bounds(const Transform&, const CharstringContext&, int bounds[4], int& width);
static bool bounds(const CharstringContext&,
double bounds[4], double& width);
static bool bounds(const Transform&, const CharstringContext&,
double bounds[4], double& width);
private:
......
......@@ -138,7 +138,7 @@ class Type1Charstring : public Charstring { public:
inline const uint8_t *data() const;
int length() const { return _s.length(); }
operator bool() const { return _s.length() != 0; }
operator String::unspecified_bool_type() const { return _s; }
inline const String &data_string() const;
inline String substring(int pos, int len) const;
......@@ -184,7 +184,9 @@ struct CharstringContext {
CharstringContext(const CharstringProgram *program_, const Charstring *cs_) : program(program_), cs(cs_) { }
operator bool() const { return cs != 0; }
operator String::unspecified_bool_type() const {
return cs != 0 ? &String::length : 0;
}
const CharstringProgram *program;
const Charstring *cs;
......@@ -194,12 +196,12 @@ struct CharstringContext {
class CharstringProgram { public:
CharstringProgram() : _parent_program(false) { }
explicit CharstringProgram(unsigned units_per_em);
virtual ~CharstringProgram() { }
virtual PermString font_name() const { return PermString(); }
virtual void font_matrix(double[6]) const;
virtual int units_per_em() const;
unsigned units_per_em() const { return _units_per_em; }
inline const CharstringProgram *program(int) const;
virtual const CharstringProgram *child_program(int) const;
......@@ -239,6 +241,7 @@ class CharstringProgram { public:
private:
bool _parent_program;
uint16_t _units_per_em;
};
......
......@@ -11,8 +11,6 @@ class TrueTypeBoundsCharstringProgram : public CharstringProgram { public:
TrueTypeBoundsCharstringProgram(const OpenType::Font *);
~TrueTypeBoundsCharstringProgram();
int units_per_em() const;
int nglyphs() const;
Charstring *glyph(int gi) const;
PermString glyph_name(int gi) const;
......@@ -24,7 +22,6 @@ class TrueTypeBoundsCharstringProgram : public CharstringProgram { public:
int _nglyphs;
int _nhmtx;
bool _loca_long;
int _units_per_em;
OpenType::Data _loca;
OpenType::Data _glyf;
OpenType::Data _hmtx;
......
......@@ -24,7 +24,7 @@ class Transform { public:
void translate(double, double);
void translate(const Point &p) { translate(p.x, p.y); }
void shear(double);
inline void transform(const Transform &);
Transform& operator*=(const Transform& x);
inline Transform scaled(double, double) const;
Transform scaled(const Point &p) const { return scaled(p.x, p.y); }
......@@ -33,7 +33,6 @@ class Transform { public:
inline Transform translated(double, double) const;
inline Transform translated(const Point &p) const;
inline Transform sheared(double) const;
Transform transformed(const Transform &) const;
// Transform operator+(Transform, const Point &);
// Transform &operator+=(Transform &, const Point &);
......@@ -119,29 +118,12 @@ operator*=(Transform &t, double scale)
return t;
}
inline Transform
operator*(Transform t, double scale)
{
inline Transform operator*(Transform t, double scale) {
return t *= scale;
}
inline Transform
operator*(const Transform &t, const Transform &tt)
{
return t.transformed(tt);
}
inline Transform &
operator*=(Transform &t, const Transform &tt)
{
t = t.transformed(tt);
return t;
}
inline void
Transform::transform(const Transform &t)
{
*this *= t;
inline Transform operator*(Transform a, const Transform& b) {
return a *= b;
}
......
......@@ -2,7 +2,7 @@
/* cff.{cc,hh} -- Compact Font Format fonts
*
* Copyright (c) 1998-2012 Eddie Kohler
* Copyright (c) 1998-2014 Eddie Kohler
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
......@@ -332,7 +332,8 @@ default_dict()
static Cff *cff;
static Cff::Font *cfffont;
if (!cfffont) {
cff = new Cff(String::make_stable((const char *) default_dict_cff_data, sizeof(default_dict_cff_data)), ErrorHandler::default_handler());
cff = new Cff(String::make_stable((const char *) default_dict_cff_data, sizeof(default_dict_cff_data)),
0, ErrorHandler::default_handler());
cfffont = (Cff::Font *) cff->font();
}
return cfffont->top_dict();
......@@ -342,9 +343,9 @@ default_dict()
#define POS_GT(pos1, pos2) ((unsigned)(pos1) > (unsigned)(pos2))
Cff::Cff(const String &s, ErrorHandler *errh)
Cff::Cff(const String& s, unsigned units_per_em, ErrorHandler* errh)
: _data_string(s), _data(reinterpret_cast<const uint8_t *>(_data_string.data())), _len(_data_string.length()),
_strings_map(-2)
_strings_map(-2), _units_per_em(units_per_em)
{
static_assert((sizeof(standard_strings) / sizeof(standard_strings[0])) == NSTANDARD_STRINGS,
"NSTANDARD_STRINGS defined incorrectly");
......@@ -1203,8 +1204,8 @@ handle_private(Cff *cff, const Cff::Dict &top_dict, Cff::Dict &private_dict,
}
Cff::FontParent::FontParent(Cff *cff)
: _cff(cff), _error(-1)
Cff::FontParent::FontParent(Cff* cff)
: CharstringProgram(cff->units_per_em()), _cff(cff), _error(-1)
{
}
......
......@@ -25,13 +25,14 @@
#include <algorithm>
#include <efont/otfdata.hh> // for ntohl()
#include <efont/otfname.hh>
#include <efont/ttfhead.hh>
namespace Efont { namespace OpenType {
Vector<PermString> debug_glyph_names;
Font::Font(const String &s, ErrorHandler *errh)
: _str(s) {
Font::Font(const String& s, ErrorHandler* errh)
: _str(s), _units_per_em(0) {
_str.align(4);
_error = parse_header(errh ? errh : ErrorHandler::silent_handler());
}
......@@ -73,6 +74,10 @@ Font::parse_header(ErrorHandler *errh)
return errh->error("tags out of order"), -EINVAL;
if (offset + length > (uint32_t) len)
return errh->error("OTF data for %<%s%> out of range", Tag(tag).text().c_str()), -EFAULT;
if (Tag::head_tag() == tag) {
Head head(_str.substring(offset, length));
_units_per_em = head.units_per_em();
}
last_tag = tag;
}
......
......@@ -2,7 +2,7 @@
/* otfdata.{cc,hh} -- OpenType bounds-checked string type
*
* Copyright (c) 2003-2012 Eddie Kohler
* Copyright (c) 2003-2014 Eddie Kohler
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
......
......@@ -2,7 +2,7 @@
/* t1bounds.{cc,hh} -- charstring bounding box finder
*
* Copyright (c) 1998-2012 Eddie Kohler
* Copyright (c) 1998-2014 Eddie Kohler
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
......@@ -97,7 +97,7 @@ CharstringBounds::set_xf(const CharstringProgram *program)
_last_xf_program = program;
double matrix[6];
program->font_matrix(matrix);
Transform font_xf = Transform(matrix).scaled(1000);
Transform font_xf = Transform(matrix).scaled(program->units_per_em());
font_xf.check_null(0.001);
_xf = _nonfont_xf * font_xf;
}
......@@ -123,27 +123,28 @@ CharstringBounds::translate(double dx, double dy)
}
bool
CharstringBounds::output(int bb[4], int &width, bool use_cur_width) const
CharstringBounds::output(double bb[4], double& width, bool use_cur_width) const
{
if (!KNOWN(_lb.x))
bb[0] = bb[1] = bb[2] = bb[3] = 0;
else {
bb[0] = (int) floor(_lb.x);
bb[1] = (int) floor(_lb.y);
bb[2] = (int) ceil(_rt.x);
bb[3] = (int) ceil(_rt.y);
bb[0] = _lb.x;
bb[1] = _lb.y;
bb[2] = _rt.x;
bb[3] = _rt.y;
}
Point p;
if (use_cur_width)
p = _width * _xf;
else
p = Point(0, 0) * _xf;
width = (int) ceil(p.x);
width = p.x;
return error() >= 0;
}
bool
CharstringBounds::bounds(const Transform &transform, const CharstringContext &g, int bb[4], int &width)
CharstringBounds::bounds(const Transform& transform, const CharstringContext& g,
double bb[4], double& width)
{
CharstringBounds b(transform);
b.char_bounds(g, false);
......@@ -151,7 +152,8 @@ CharstringBounds::bounds(const Transform &transform, const CharstringContext &g,
}
bool
CharstringBounds::bounds(const CharstringContext &g, int bb[4], int &width)
CharstringBounds::bounds(const CharstringContext &g,
double bb[4], double& width)
{
CharstringBounds b;
b.char_bounds(g, false);
......
......@@ -2,7 +2,7 @@
/* t1cs.{cc,hh} -- Type 1/2 charstrings
*
* Copyright (c) 1998-2012 Eddie Kohler
* Copyright (c) 1998-2014 Eddie Kohler
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
......@@ -326,6 +326,11 @@ Type2Charstring::process(CharstringInterp &interp) const
}
CharstringProgram::CharstringProgram(unsigned units_per_em)
: _parent_program(false),
_units_per_em(units_per_em ? units_per_em : 1000) {
}
const CharstringProgram *
CharstringProgram::child_program(int) const
{
......@@ -339,12 +344,6 @@ CharstringProgram::font_matrix(double matrix[6]) const
matrix[1] = matrix[2] = matrix[4] = matrix[5] = 0;
}
int
CharstringProgram::units_per_em() const
{
return 1000;
}
void
CharstringProgram::glyph_names(Vector<PermString> &gnames) const
{
......
......@@ -2,7 +2,7 @@
/* t1font.{cc,hh} -- Type 1 font
*
* Copyright (c) 1998-2012 Eddie Kohler
* Copyright (c) 1998-2014 Eddie Kohler
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
......@@ -31,7 +31,8 @@ static PermString lenIV_str = "lenIV";
static PermString FontInfo_str = "FontInfo";
Type1Font::Type1Font(PermString name)
: _cached_defs(false), _built(true), _font_name(name), _glyph_map(-1),
: CharstringProgram(1000),
_cached_defs(false), _built(true), _font_name(name), _glyph_map(-1),
_encoding(0), _cached_mmspace(0), _mmspace(0), _synthetic_item(0)
{
_dict = new HashMap<PermString, Type1Definition *>[dLast];
......@@ -43,7 +44,8 @@ Type1Font::Type1Font(PermString name)
}
Type1Font::Type1Font(Type1Reader &reader)
: _cached_defs(false), _built(false), _glyph_map(-1), _encoding(0),
: CharstringProgram(1000),
_cached_defs(false), _built(false), _glyph_map(-1), _encoding(0),
_cached_mmspace(0), _mmspace(0), _synthetic_item(0)
{
_dict = new HashMap<PermString, Type1Definition *>[dLast];
......
......@@ -2,7 +2,7 @@
/* t1mm.{cc,hh} -- Type 1 multiple master font information
*
* Copyright (c) 1998-2012 Eddie Kohler
* Copyright (c) 1998-2014 Eddie Kohler
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
......@@ -25,7 +25,8 @@
namespace Efont {
MultipleMasterSpace::MultipleMasterSpace(PermString fn, int na, int nm)
: _ok(false), _font_name(fn), _naxes(na), _nmasters(nm),
: CharstringProgram(1000),
_ok(false), _font_name(fn), _naxes(na), _nmasters(nm),
_axis_types(na, PermString()), _axis_labels(na, PermString()),
_design_vector(0), _norm_design_vector(0), _weight_vector(0)
{
......
......@@ -2,7 +2,7 @@
/* ttfcs.{cc,hh} -- TrueType "charstring" emulation
*
* Copyright (c) 2006-2012 Eddie Kohler
* Copyright (c) 2006-2014 Eddie Kohler
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
......@@ -24,8 +24,9 @@
#include <lcdf/hashmap.hh>
namespace Efont {
TrueTypeBoundsCharstringProgram::TrueTypeBoundsCharstringProgram(const OpenType::Font *otf)
: _otf(otf), _nglyphs(-1), _loca_long(false), _units_per_em(1024),
TrueTypeBoundsCharstringProgram::TrueTypeBoundsCharstringProgram(const OpenType::Font* otf)
: CharstringProgram(otf->units_per_em()),
_otf(otf), _nglyphs(-1), _loca_long(false),
_loca(otf->table("loca")), _glyf(otf->table("glyf")),
_hmtx(otf->table("hmtx")), _got_glyph_names(false), _got_unicodes(false)
{
......@@ -34,10 +35,8 @@ TrueTypeBoundsCharstringProgram::TrueTypeBoundsCharstringProgram(const OpenType:
_nglyphs = maxp.u16(4);
OpenType::Head head(otf->table("head"), 0);
if (head.ok()) {
if (head.ok())
_loca_long = head.index_to_loc_format() != 0;
_units_per_em = head.units_per_em();
}
if (_loca_long)
_loca.align_long();
int loca_onesize = (_loca_long ? 4 : 2);
......@@ -77,12 +76,6 @@ TrueTypeBoundsCharstringProgram::~TrueTypeBoundsCharstringProgram()
delete *cs;
}
int
TrueTypeBoundsCharstringProgram::units_per_em() const
{
return _units_per_em;
}
int
TrueTypeBoundsCharstringProgram::nglyphs() const
{
......
......@@ -2,7 +2,7 @@
/* transform.{cc,hh} -- planar affine transformations
*
* Copyright (c) 2000-2012 Eddie Kohler
* Copyright (c) 2000-2014 Eddie Kohler
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
......@@ -105,15 +105,22 @@ Transform::shear(double s)
*this *= Transform(1, 0, s, 1, 0, 0);
}
Transform
Transform::transformed(const Transform &t) const
{
return Transform(_m[0] * t._m[0] + _m[2] * t._m[1],
_m[1] * t._m[0] + _m[3] * t._m[1],
_m[0] * t._m[2] + _m[2] * t._m[3],
_m[1] * t._m[2] + _m[3] * t._m[3],
_m[0] * t._m[4] + _m[2] * t._m[5] + _m[4],
_m[1] * t._m[4] + _m[3] * t._m[5] + _m[5]);
Transform& Transform::operator*=(const Transform& x) {
if (x.null())
/* do nothing */;
else if (null())
memcpy(_m, x._m, sizeof(_m));
else {
double m[6];
m[0] = _m[0] * x._m[0] + _m[2] * x._m[1];
m[1] = _m[1] * x._m[0] + _m[3] * x._m[1];
m[2] = _m[0] * x._m[2] + _m[2] * x._m[3];
m[3] = _m[1] * x._m[2] + _m[3] * x._m[3];
m[4] = _m[0] * x._m[4] + _m[2] * x._m[5] + _m[4];
m[5] = _m[1] * x._m[4] + _m[3] * x._m[5] + _m[5];
memcpy(_m, m, sizeof(_m));
}
return *this;
}
......
/* otfinfo.cc -- driver for reporting information about OpenType fonts
*
* Copyright (c) 2003-2013 Eddie Kohler
* Copyright (c) 2003-2014 Eddie Kohler
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
......@@ -427,7 +427,7 @@ do_query_glyphs(const OpenType::Font &otf, ErrorHandler *errh, ErrorHandler *res
int before_nerrors = errh->nerrors();
try {
// get font
Cff cff(otf.table("CFF"), errh);
Cff cff(otf.table("CFF"), otf.units_per_em(), errh);
if (!cff.ok())
throw OpenType::Error();
......
/* otftotfm.cc -- driver for translating OpenType fonts to TeX metrics
*
* Copyright (c) 2003-2013 Eddie Kohler
* Copyright (c) 2003-2014 Eddie Kohler
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
......@@ -511,29 +511,43 @@ lig_context_str(int ctx)
static double max_printed_real;
static void
fprint_real(FILE *f, const char *prefix, double value, double du, const char *suffix = ")\n")
{
if (du == 1.) {
fprintf(f, "%s R %g%s", prefix, value, suffix);
max_printed_real = std::max(max_printed_real, fabs(value));
} else {
fprintf(f, "%s R %.4f%s", prefix, value * du, suffix);
max_printed_real = std::max(max_printed_real, fabs(value * du));
namespace {
struct Printer {
Printer(FILE* f, unsigned design_units, unsigned units_per_em)
: f_(f), du_((double) design_units / units_per_em),
round_(design_units == 1000) {
}
void print(const char* prefix, double value, const char* suffix = ")\n") const;
String render(double value) const;
FILE* f_;
double du_;
bool round_;
};
void Printer::print(const char* prefix, double value, const char* suffix) const {
value *= du_;
if (round_)
value = ceil(value);
if (round_ || value - floor(value) < 0.01)
fprintf(f_, "%s R %g%s", prefix, value, suffix);
else
fprintf(f_, "%s R %.4f%s", prefix, value, suffix);
max_printed_real = std::max(max_printed_real, fabs(value));
}
static String
real_string(double value, double du)
{
if (du == 1.)
String Printer::render(double value) const {
value *= du_;
if (round_)
value = ceil(value);
if (round_ || value - floor(value) < 0.01)
return String(value);
else {
char buf[128];
sprintf(buf, "%.4f", value * du);
sprintf(buf, "%.4f", value);
return String(buf);
}
}
} // namespace
double
font_slant(const FontInfo &finfo)
......@@ -591,8 +605,8 @@ output_pl(Metrics &metrics, const String &ps_name, int boundary_char,
font_xform.scale(extend, 1);
if (slant)
font_xform.shear(slant);
int bounds[4], width;
double du = (design_units == metrics.units_per_em() ? 1. : design_units / (double) metrics.units_per_em());
double bounds[4], width;
Printer pr(f, design_units, metrics.units_per_em());
double actual_slant = font_slant(finfo);
if (actual_slant)
......@@ -601,24 +615,24 @@ output_pl(Metrics &metrics, const String &ps_name, int boundary_char,
if (char_bounds(bounds, width, finfo, font_xform, ' ')) {
// advance space width by letterspacing, scale by space_factor
double space_width = (width + (vpl ? letterspace : 0)) * space_factor;
fprint_real(f, " (SPACE", space_width, du);
pr.print(" (SPACE", space_width);
if (finfo.is_fixed_pitch()) {
// fixed-pitch: no space stretch or shrink
fprint_real(f, " (STRETCH", 0, du);
fprint_real(f, " (SHRINK", 0, du);
fprint_real(f, " (EXTRASPACE", space_width, du);
pr.print(" (STRETCH", 0);
pr.print(" (SHRINK", 0);
pr.print(" (EXTRASPACE", space_width);