reactos/rosapps/smartpdf/fitz/mupdf/pdf_font.c
Klemens Friedl c0ff78a908 two linking issues fixed
* _wstr_dup
* _FT_Get_X11_Font_Format (with a work-around)

one weird mingw linking issue remains:
* _WinMain@16


trunk/reactos/lib/3rdparty/mingw/main.c:73: undefined reference to `_WinMain@16'

svn path=/trunk/; revision=29315
2007-09-30 15:43:34 +00:00

1042 lines
23 KiB
C

#include <fitz.h>
#include <mupdf.h>
#define noHINT
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_XFREE86_H
static char *basefontnames[14][7] =
{
{ "Courier", "CourierNew", "CourierNewPSMT", 0 },
{ "Courier-Bold", "CourierNew,Bold", "Courier,Bold",
"CourierNewPS-BoldMT", "CourierNew-Bold", 0 },
{ "Courier-Oblique", "CourierNew,Italic", "Courier,Italic",
"CourierNewPS-ItalicMT", "CourierNew-Italic", 0 },
{ "Courier-BoldOblique", "CourierNew,BoldItalic", "Courier,BoldItalic",
"CourierNewPS-BoldItalicMT", "CourierNew-BoldItalic", 0 },
{ "Helvetica", "ArialMT", "Arial", 0 },
{ "Helvetica-Bold", "Arial-BoldMT", "Arial,Bold", "Arial-Bold",
"Helvetica,Bold", 0 },
{ "Helvetica-Oblique", "Arial-ItalicMT", "Arial,Italic", "Arial-Italic",
"Helvetica,Italic", "Helvetica-Italic", 0 },
{ "Helvetica-BoldOblique", "Arial-BoldItalicMT",
"Arial,BoldItalic", "Arial-BoldItalic",
"Helvetica,BoldItalic", "Helvetica-BoldItalic", 0 },
{ "Times-Roman", "TimesNewRomanPSMT", "TimesNewRoman",
"TimesNewRomanPS", 0 },
{ "Times-Bold", "TimesNewRomanPS-BoldMT", "TimesNewRoman,Bold",
"TimesNewRomanPS-Bold", "TimesNewRoman-Bold", 0 },
{ "Times-Italic", "TimesNewRomanPS-ItalicMT", "TimesNewRoman,Italic",
"TimesNewRomanPS-Italic", "TimesNewRoman-Italic", 0 },
{ "Times-BoldItalic", "TimesNewRomanPS-BoldItalicMT",
"TimesNewRoman,BoldItalic", "TimesNewRomanPS-BoldItalic",
"TimesNewRoman-BoldItalic", 0 },
{ "Symbol", 0 },
{ "ZapfDingbats", 0 }
};
/*
* FreeType and Rendering glue
*/
enum { UNKNOWN, TYPE1, TRUETYPE, CID };
static int ftkind(FT_Face face)
{
/*const char *kind = FT_Get_X11_Font_Format(face);
pdf_logfont("ft font format %s\n", kind);
if (!strcmp(kind, "TrueType"))
return TRUETYPE;
if (!strcmp(kind, "Type 1"))
return TYPE1;
if (!strcmp(kind, "CFF"))
return TYPE1;
if (!strcmp(kind, "CID Type 1"))
return TYPE1;
return UNKNOWN;*/
/* @note: work-around */
return TYPE1;
}
static inline int ftcidtogid(pdf_font *font, int cid)
{
if (font->tottfcmap)
{
cid = pdf_lookupcmap(font->tottfcmap, cid);
return FT_Get_Char_Index(font->ftface, cid);
}
if (font->cidtogid)
return font->cidtogid[cid];
return cid;
}
static int ftwidth(pdf_font *font, int cid)
{
int e;
cid = ftcidtogid(font, cid);
e = FT_Load_Glyph(font->ftface, cid,
FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM);
if (e)
return 0;
return ((FT_Face)font->ftface)->glyph->advance.x;
}
static fz_error *
ftrender(fz_glyph *glyph, fz_font *fzfont, int cid, fz_matrix trm)
{
pdf_font *font = (pdf_font*)fzfont;
FT_Face face = font->ftface;
FT_Matrix m;
FT_Vector v;
FT_Error fterr;
float scale;
int gid;
int x, y;
gid = ftcidtogid(font, cid);
if (font->substitute && fzfont->wmode == 0)
{
fz_hmtx subw;
int realw;
FT_Set_Char_Size(face, 1000, 1000, 72, 72);
fterr = FT_Load_Glyph(font->ftface, gid,
FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM);
if (fterr)
return fz_throw("freetype failed to load glyph: 0x%x", fterr);
realw = ((FT_Face)font->ftface)->glyph->advance.x;
subw = fz_gethmtx(fzfont, cid);
if (realw)
scale = (float) subw.w / realw;
else
scale = 1.0;
trm = fz_concat(fz_scale(scale, 1.0), trm);
}
glyph->w = 0;
glyph->h = 0;
glyph->x = 0;
glyph->y = 0;
glyph->samples = nil;
/* freetype mutilates complex glyphs if they are loaded
* with FT_Set_Char_Size 1.0. it rounds the coordinates
* before applying transformation. to get more precision in
* freetype, we shift part of the scale in the matrix
* into FT_Set_Char_Size instead
*/
#ifdef HINT
scale = fz_matrixexpansion(trm);
m.xx = trm.a * 65536 / scale;
m.yx = trm.b * 65536 / scale;
m.xy = trm.c * 65536 / scale;
m.yy = trm.d * 65536 / scale;
v.x = 0;
v.y = 0;
FT_Set_Char_Size(face, 64 * scale, 64 * scale, 72, 72);
FT_Set_Transform(face, &m, &v);
fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP);
if (fterr)
fz_warn("freetype load glyph: 0x%x", fterr);
#else
m.xx = trm.a * 64; /* should be 65536 */
m.yx = trm.b * 64;
m.xy = trm.c * 64;
m.yy = trm.d * 64;
v.x = trm.e * 64;
v.y = trm.f * 64;
FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */
FT_Set_Transform(face, &m, &v);
fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
if (fterr)
fz_warn("freetype load glyph: 0x%x", fterr);
#endif
fterr = FT_Render_Glyph(face->glyph, ft_render_mode_normal);
if (fterr)
fz_warn("freetype render glyph: 0x%x", fterr);
glyph->w = face->glyph->bitmap.width;
glyph->h = face->glyph->bitmap.rows;
glyph->x = face->glyph->bitmap_left;
glyph->y = face->glyph->bitmap_top - glyph->h;
glyph->samples = face->glyph->bitmap.buffer;
for (y = 0; y < glyph->h / 2; y++)
{
for (x = 0; x < glyph->w; x++)
{
unsigned char a = glyph->samples[y * glyph->w + x ];
unsigned char b = glyph->samples[(glyph->h - y - 1) * glyph->w + x];
glyph->samples[y * glyph->w + x ] = b;
glyph->samples[(glyph->h - y - 1) * glyph->w + x] = a;
}
}
return nil;
}
/*
* Basic encoding tables
*/
static char *cleanfontname(char *fontname)
{
int i, k;
for (i = 0; i < 14; i++)
for (k = 0; basefontnames[i][k]; k++)
if (!strcmp(basefontnames[i][k], fontname))
return basefontnames[i][0];
return fontname;
}
static int mrecode(char *name)
{
int i;
for (i = 0; i < 256; i++)
if (pdf_macroman[i] && !strcmp(name, pdf_macroman[i]))
return i;
return -1;
}
/*
* Create and destroy
*/
static void ftdropfont(fz_font *font)
{
pdf_font *pfont = (pdf_font*)font;
if (pfont->encoding)
pdf_dropcmap(pfont->encoding);
if (pfont->tottfcmap)
pdf_dropcmap(pfont->tottfcmap);
if (pfont->tounicode)
pdf_dropcmap(pfont->tounicode);
fz_free(pfont->cidtogid);
fz_free(pfont->cidtoucs);
if (pfont->ftface)
FT_Done_Face((FT_Face)pfont->ftface);
if (pfont->fontdata)
fz_dropbuffer(pfont->fontdata);
}
pdf_font *
pdf_newfont(char *name)
{
pdf_font *font;
int i;
font = fz_malloc(sizeof (pdf_font));
if (!font)
return nil;
fz_initfont((fz_font*)font, name);
font->super.render = ftrender;
font->super.drop = (void(*)(fz_font*)) ftdropfont;
font->ftface = nil;
font->substitute = 0;
font->flags = 0;
font->italicangle = 0;
font->ascent = 0;
font->descent = 0;
font->capheight = 0;
font->xheight = 0;
font->missingwidth = 0;
font->encoding = nil;
font->tottfcmap = 0;
font->ncidtogid = 0;
font->cidtogid = nil;
font->tounicode = nil;
font->ncidtoucs = 0;
font->cidtoucs = nil;
font->filename = nil;
font->fontdata = nil;
for (i = 0; i < 256; i++)
font->charprocs[i] = nil;
return font;
}
/*
* Simple fonts (Type1 and TrueType)
*/
static fz_error *
loadsimplefont(pdf_font **fontp, pdf_xref *xref, fz_obj *dict, fz_obj *ref)
{
fz_error *error;
fz_obj *descriptor = nil;
fz_obj *encoding = nil;
fz_obj *widths = nil;
unsigned short *etable = nil;
pdf_font *font;
fz_irect bbox;
FT_Face face;
FT_CharMap cmap;
int kind;
int symbolic;
char *basefont;
char *fontname;
char *estrings[256];
char ebuffer[256][32];
int i, k, n, e;
basefont = fz_toname(fz_dictgets(dict, "BaseFont"));
fontname = cleanfontname(basefont);
/*
* Load font file
*/
font = pdf_newfont(fontname);
if (!font)
return fz_outofmem;
pdf_logfont("load simple font %d %d (%p) {\n", fz_tonum(ref), fz_togen(ref), font);
pdf_logfont("basefont0 %s\n", basefont);
pdf_logfont("basefont1 %s\n", fontname);
descriptor = fz_dictgets(dict, "FontDescriptor");
if (descriptor && basefont == fontname)
error = pdf_loadfontdescriptor(font, xref, descriptor, nil);
else
error = pdf_loadbuiltinfont(font, fontname);
if (error)
goto cleanup;
face = font->ftface;
kind = ftkind(face);
pdf_logfont("ft name '%s' '%s'\n", face->family_name, face->style_name);
bbox.x0 = (face->bbox.xMin * 1000) / face->units_per_EM;
bbox.y0 = (face->bbox.yMin * 1000) / face->units_per_EM;
bbox.x1 = (face->bbox.xMax * 1000) / face->units_per_EM;
bbox.y1 = (face->bbox.yMax * 1000) / face->units_per_EM;
pdf_logfont("ft bbox [%d %d %d %d]\n", bbox.x0, bbox.y0, bbox.x1, bbox.y1);
if (bbox.x0 == bbox.x1)
fz_setfontbbox((fz_font*)font, -1000, -1000, 2000, 2000);
else
fz_setfontbbox((fz_font*)font, bbox.x0, bbox.y0, bbox.x1, bbox.y1);
/*
* Encoding
*/
symbolic = font->flags & 4;
if (face->num_charmaps > 0)
cmap = face->charmaps[0];
else
cmap = nil;
for (i = 0; i < face->num_charmaps; i++)
{
FT_CharMap test = face->charmaps[i];
if (kind == TYPE1)
{
if (test->platform_id == 7)
cmap = test;
}
if (kind == TRUETYPE)
{
if (test->platform_id == 1 && test->encoding_id == 0)
cmap = test;
if (test->platform_id == 3 && test->encoding_id == 1)
cmap = test;
}
}
if (cmap)
{
e = FT_Set_Charmap(face, cmap);
if (e)
{
error = fz_throw("freetype could not set cmap: 0x%x", e);
goto cleanup;
}
}
else
fz_warn("freetype could not find any cmaps");
etable = fz_malloc(sizeof(unsigned short) * 256);
if (!etable)
goto cleanup;
for (i = 0; i < 256; i++)
{
estrings[i] = nil;
etable[i] = 0;
}
encoding = fz_dictgets(dict, "Encoding");
if (encoding && !(kind == TRUETYPE && symbolic))
{
error = pdf_resolve(&encoding, xref);
if (error)
goto cleanup;
if (fz_isname(encoding))
pdf_loadencoding(estrings, fz_toname(encoding));
if (fz_isdict(encoding))
{
fz_obj *base, *diff, *item;
base = fz_dictgets(encoding, "BaseEncoding");
if (fz_isname(base))
pdf_loadencoding(estrings, fz_toname(base));
diff = fz_dictgets(encoding, "Differences");
if (fz_isarray(diff))
{
n = fz_arraylen(diff);
k = 0;
for (i = 0; i < n; i++)
{
item = fz_arrayget(diff, i);
if (fz_isint(item))
k = fz_toint(item);
if (fz_isname(item))
estrings[k++] = fz_toname(item);
if (k < 0) k = 0;
if (k > 255) k = 255;
}
}
}
if (kind == TYPE1)
{
pdf_logfont("encode type1/cff by strings\n");
for (i = 0; i < 256; i++)
if (estrings[i])
etable[i] = FT_Get_Name_Index(face, estrings[i]);
else
etable[i] = FT_Get_Char_Index(face, i);
}
if (kind == TRUETYPE)
{
/* Unicode cmap */
if (face->charmap->platform_id == 3)
{
pdf_logfont("encode truetype via unicode\n");
for (i = 0; i < 256; i++)
if (estrings[i])
{
int aglbuf[256];
int aglnum;
aglnum = pdf_lookupagl(estrings[i], aglbuf, nelem(aglbuf));
if (aglnum != 1)
etable[i] = FT_Get_Name_Index(face, estrings[i]);
else
etable[i] = FT_Get_Char_Index(face, aglbuf[0]);
}
else
etable[i] = FT_Get_Char_Index(face, i);
}
/* MacRoman cmap */
else if (face->charmap->platform_id == 1)
{
pdf_logfont("encode truetype via macroman\n");
for (i = 0; i < 256; i++)
if (estrings[i])
{
k = mrecode(estrings[i]);
if (k <= 0)
etable[i] = FT_Get_Name_Index(face, estrings[i]);
else
etable[i] = FT_Get_Char_Index(face, k);
}
else
etable[i] = FT_Get_Char_Index(face, i);
}
/* Symbolic cmap */
else
{
pdf_logfont("encode truetype symbolic\n");
for (i = 0; i < 256; i++)
{
etable[i] = FT_Get_Char_Index(face, i);
FT_Get_Glyph_Name(face, etable[i], ebuffer[i], 32);
if (ebuffer[i][0])
estrings[i] = ebuffer[i];
}
}
}
fz_dropobj(encoding);
}
else
{
pdf_logfont("encode builtin\n");
for (i = 0; i < 256; i++)
{
etable[i] = FT_Get_Char_Index(face, i);
FT_Get_Glyph_Name(face, etable[i], ebuffer[i], 32);
if (ebuffer[i][0])
estrings[i] = ebuffer[i];
}
}
error = pdf_newidentitycmap(&font->encoding, 0, 1);
if (error)
goto cleanup;
font->ncidtogid = 256;
font->cidtogid = etable;
error = pdf_loadtounicode(font, xref,
estrings, nil, fz_dictgets(dict, "ToUnicode"));
if (error)
goto cleanup;
/*
* Widths
*/
fz_setdefaulthmtx((fz_font*)font, font->missingwidth);
widths = fz_dictgets(dict, "Widths");
if (widths)
{
int first, last;
error = pdf_resolve(&widths, xref);
if (error)
goto cleanup;
first = fz_toint(fz_dictgets(dict, "FirstChar"));
last = fz_toint(fz_dictgets(dict, "LastChar"));
if (first < 0 || last > 255 || first > last)
first = last = 0;
for (i = 0; i < last - first + 1; i++)
{
int wid = fz_toint(fz_arrayget(widths, i));
error = fz_addhmtx((fz_font*)font, i + first, i + first, wid);
if (error)
goto cleanup;
}
fz_dropobj(widths);
}
else
{
FT_Set_Char_Size(face, 1000, 1000, 72, 72);
for (i = 0; i < 256; i++)
{
error = fz_addhmtx((fz_font*)font, i, i, ftwidth(font, i));
if (error)
goto cleanup;
}
}
error = fz_endhmtx((fz_font*)font);
if (error)
goto cleanup;
pdf_logfont("}\n");
*fontp = font;
return nil;
cleanup:
fz_free(etable);
if (widths)
fz_dropobj(widths);
fz_dropfont((fz_font*)font);
return error;
}
/*
* CID Fonts
*/
static fz_error *
loadcidfont(pdf_font **fontp, pdf_xref *xref, fz_obj *dict, fz_obj *ref, fz_obj *encoding, fz_obj *tounicode)
{
fz_error *error;
fz_obj *widths = nil;
fz_obj *descriptor;
pdf_font *font;
FT_Face face;
fz_irect bbox;
int kind;
char collection[256];
char *basefont;
int i, k;
/*
* Get font name and CID collection
*/
basefont = fz_toname(fz_dictgets(dict, "BaseFont"));
{
fz_obj *cidinfo;
fz_obj *obj;
char tmpstr[64];
int tmplen;
cidinfo = fz_dictgets(dict, "CIDSystemInfo");
error = pdf_resolve(&cidinfo, xref);
if (error)
return error;
obj = fz_dictgets(cidinfo, "Registry");
tmplen = MIN(sizeof tmpstr - 1, fz_tostrlen(obj));
memcpy(tmpstr, fz_tostrbuf(obj), tmplen);
tmpstr[tmplen] = '\0';
strlcpy(collection, tmpstr, sizeof collection);
strlcat(collection, "-", sizeof collection);
obj = fz_dictgets(cidinfo, "Ordering");
tmplen = MIN(sizeof tmpstr - 1, fz_tostrlen(obj));
memcpy(tmpstr, fz_tostrbuf(obj), tmplen);
tmpstr[tmplen] = '\0';
strlcat(collection, tmpstr, sizeof collection);
fz_dropobj(cidinfo);
}
/*
* Load font file
*/
font = pdf_newfont(basefont);
if (!font)
return fz_outofmem;
pdf_logfont("load cid font %d %d (%p) {\n", fz_tonum(ref), fz_togen(ref), font);
pdf_logfont("basefont %s\n", basefont);
pdf_logfont("collection %s\n", collection);
descriptor = fz_dictgets(dict, "FontDescriptor");
if (descriptor)
error = pdf_loadfontdescriptor(font, xref, descriptor, collection);
else
error = fz_throw("syntaxerror: missing font descriptor");
if (error)
goto cleanup;
face = font->ftface;
kind = ftkind(face);
bbox.x0 = (face->bbox.xMin * 1000) / face->units_per_EM;
bbox.y0 = (face->bbox.yMin * 1000) / face->units_per_EM;
bbox.x1 = (face->bbox.xMax * 1000) / face->units_per_EM;
bbox.y1 = (face->bbox.yMax * 1000) / face->units_per_EM;
pdf_logfont("ft bbox [%d %d %d %d]\n", bbox.x0, bbox.y0, bbox.x1, bbox.y1);
if (bbox.x0 == bbox.x1)
fz_setfontbbox((fz_font*)font, -1000, -1000, 2000, 2000);
else
fz_setfontbbox((fz_font*)font, bbox.x0, bbox.y0, bbox.x1, bbox.y1);
/*
* Encoding
*/
if (fz_isname(encoding))
{
pdf_logfont("encoding /%s\n", fz_toname(encoding));
if (!strcmp(fz_toname(encoding), "Identity-H"))
error = pdf_newidentitycmap(&font->encoding, 0, 2);
else if (!strcmp(fz_toname(encoding), "Identity-V"))
error = pdf_newidentitycmap(&font->encoding, 1, 2);
else
error = pdf_loadsystemcmap(&font->encoding, fz_toname(encoding));
}
else if (fz_isindirect(encoding))
{
pdf_logfont("encoding %d %d R\n", fz_tonum(encoding), fz_togen(encoding));
error = pdf_loadembeddedcmap(&font->encoding, xref, encoding);
}
else
{
error = fz_throw("syntaxerror: font missing encoding");
}
if (error)
goto cleanup;
fz_setfontwmode((fz_font*)font, pdf_getwmode(font->encoding));
pdf_logfont("wmode %d\n", pdf_getwmode(font->encoding));
if (kind == TRUETYPE)
{
fz_obj *cidtogidmap;
cidtogidmap = fz_dictgets(dict, "CIDToGIDMap");
if (fz_isindirect(cidtogidmap))
{
unsigned short *map;
fz_buffer *buf;
int len;
pdf_logfont("cidtogidmap stream\n");
error = pdf_loadstream(&buf, xref, fz_tonum(cidtogidmap), fz_togen(cidtogidmap));
if (error)
goto cleanup;
len = (buf->wp - buf->rp) / 2;
map = fz_malloc(len * sizeof(unsigned short));
if (!map) {
fz_dropbuffer(buf);
error = fz_outofmem;
goto cleanup;
}
for (i = 0; i < len; i++)
map[i] = (buf->rp[i * 2] << 8) + buf->rp[i * 2 + 1];
font->ncidtogid = len;
font->cidtogid = map;
fz_dropbuffer(buf);
}
/* if truetype font is external, cidtogidmap should not be identity */
/* so we map from cid to unicode and then map that through the (3 1) */
/* unicode cmap to get a glyph id */
else if (font->substitute)
{
int e;
pdf_logfont("emulate ttf cidfont\n");
e = FT_Select_Charmap(face, ft_encoding_unicode);
if (e)
return fz_throw("fonterror: no unicode cmap when emulating CID font");
if (!strcmp(collection, "Adobe-CNS1"))
error = pdf_loadsystemcmap(&font->tottfcmap, "Adobe-CNS1-UCS2");
else if (!strcmp(collection, "Adobe-GB1"))
error = pdf_loadsystemcmap(&font->tottfcmap, "Adobe-GB1-UCS2");
else if (!strcmp(collection, "Adobe-Japan1"))
error = pdf_loadsystemcmap(&font->tottfcmap, "Adobe-Japan1-UCS2");
else if (!strcmp(collection, "Adobe-Japan2"))
error = pdf_loadsystemcmap(&font->tottfcmap, "Adobe-Japan2-UCS2");
else if (!strcmp(collection, "Adobe-Korea1"))
error = pdf_loadsystemcmap(&font->tottfcmap, "Adobe-Korea1-UCS2");
else
error = nil;
if (error)
return error;
}
}
error = pdf_loadtounicode(font, xref, nil, collection, tounicode);
if (error)
goto cleanup;
/*
* Horizontal
*/
fz_setdefaulthmtx((fz_font*)font, fz_toint(fz_dictgets(dict, "DW")));
widths = fz_dictgets(dict, "W");
if (widths)
{
int c0, c1, w;
fz_obj *obj;
error = pdf_resolve(&widths, xref);
if (error)
goto cleanup;
for (i = 0; i < fz_arraylen(widths); )
{
c0 = fz_toint(fz_arrayget(widths, i));
obj = fz_arrayget(widths, i + 1);
if (fz_isarray(obj))
{
for (k = 0; k < fz_arraylen(obj); k++)
{
w = fz_toint(fz_arrayget(obj, k));
error = fz_addhmtx((fz_font*)font, c0 + k, c0 + k, w);
if (error)
goto cleanup;
}
i += 2;
}
else
{
c1 = fz_toint(obj);
w = fz_toint(fz_arrayget(widths, i + 2));
error = fz_addhmtx((fz_font*)font, c0, c1, w);
if (error)
goto cleanup;
i += 3;
}
}
fz_dropobj(widths);
}
error = fz_endhmtx((fz_font*)font);
if (error)
goto cleanup;
/*
* Vertical
*/
if (pdf_getwmode(font->encoding) == 1)
{
fz_obj *obj;
int dw2y = 880;
int dw2w = -1000;
obj = fz_dictgets(dict, "DW2");
if (obj)
{
dw2y = fz_toint(fz_arrayget(obj, 0));
dw2w = fz_toint(fz_arrayget(obj, 1));
}
fz_setdefaultvmtx((fz_font*)font, dw2y, dw2w);
widths = fz_dictgets(dict, "W2");
if (widths)
{
int c0, c1, w, x, y, k;
error = pdf_resolve(&widths, xref);
if (error)
goto cleanup;
for (i = 0; i < fz_arraylen(widths); )
{
c0 = fz_toint(fz_arrayget(widths, i));
obj = fz_arrayget(widths, i + 1);
if (fz_isarray(obj))
{
for (k = 0; k < fz_arraylen(obj); k += 3)
{
w = fz_toint(fz_arrayget(obj, k + 0));
x = fz_toint(fz_arrayget(obj, k + 1));
y = fz_toint(fz_arrayget(obj, k + 2));
error = fz_addvmtx((fz_font*)font, c0 + k, c0 + k, x, y, w);
if (error)
goto cleanup;
}
i += 2;
}
else
{
c1 = fz_toint(obj);
w = fz_toint(fz_arrayget(widths, i + 2));
x = fz_toint(fz_arrayget(widths, i + 3));
y = fz_toint(fz_arrayget(widths, i + 4));
error = fz_addvmtx((fz_font*)font, c0, c1, x, y, w);
if (error)
goto cleanup;
i += 5;
}
}
fz_dropobj(widths);
}
error = fz_endvmtx((fz_font*)font);
if (error)
goto cleanup;
}
pdf_logfont("}\n");
*fontp = font;
return nil;
cleanup:
if (widths)
fz_dropobj(widths);
fz_dropfont((fz_font*)font);
return error;
}
static fz_error *
loadtype0(pdf_font **fontp, pdf_xref *xref, fz_obj *dict, fz_obj *ref)
{
fz_error *error;
fz_obj *dfonts;
fz_obj *dfont;
fz_obj *subtype;
fz_obj *encoding;
fz_obj *tounicode;
dfonts = fz_dictgets(dict, "DescendantFonts");
error = pdf_resolve(&dfonts, xref);
if (error)
return error;
dfont = fz_arrayget(dfonts, 0);
error = pdf_resolve(&dfont, xref);
if (error)
return fz_dropobj(dfonts), error;
subtype = fz_dictgets(dfont, "Subtype");
encoding = fz_dictgets(dict, "Encoding");
tounicode = fz_dictgets(dict, "ToUnicode");
if (!strcmp(fz_toname(subtype), "CIDFontType0"))
error = loadcidfont(fontp, xref, dfont, ref, encoding, tounicode);
else if (!strcmp(fz_toname(subtype), "CIDFontType2"))
error = loadcidfont(fontp, xref, dfont, ref, encoding, tounicode);
else
error = fz_throw("syntaxerror: unknown cid font type");
fz_dropobj(dfont);
fz_dropobj(dfonts);
if (error)
return error;
return nil;
}
/*
* FontDescriptor
*/
fz_error *
pdf_loadfontdescriptor(pdf_font *font, pdf_xref *xref, fz_obj *desc, char *collection)
{
fz_error *error;
fz_obj *obj1, *obj2, *obj3, *obj;
fz_rect bbox;
char *fontname;
error = pdf_resolve(&desc, xref);
if (error)
return error;
pdf_logfont("load fontdescriptor {\n");
fontname = fz_toname(fz_dictgets(desc, "FontName"));
pdf_logfont("fontname %s\n", fontname);
font->flags = fz_toint(fz_dictgets(desc, "Flags"));
font->italicangle = fz_toreal(fz_dictgets(desc, "ItalicAngle"));
font->ascent = fz_toreal(fz_dictgets(desc, "Ascent"));
font->descent = fz_toreal(fz_dictgets(desc, "Descent"));
font->capheight = fz_toreal(fz_dictgets(desc, "CapHeight"));
font->xheight = fz_toreal(fz_dictgets(desc, "XHeight"));
font->missingwidth = fz_toreal(fz_dictgets(desc, "MissingWidth"));
bbox = pdf_torect(fz_dictgets(desc, "FontBBox"));
pdf_logfont("bbox [%g %g %g %g]\n",
bbox.x0, bbox.y0,
bbox.x1, bbox.y1);
pdf_logfont("flags %d\n", font->flags);
obj1 = fz_dictgets(desc, "FontFile");
obj2 = fz_dictgets(desc, "FontFile2");
obj3 = fz_dictgets(desc, "FontFile3");
obj = obj1 ? obj1 : obj2 ? obj2 : obj3;
if (getenv("NOFONT"))
obj = nil;
if (fz_isindirect(obj))
{
error = pdf_loadembeddedfont(font, xref, obj);
if (error)
goto cleanup;
}
else
{
error = pdf_loadsystemfont(font, fontname, collection);
if (error)
goto cleanup;
}
fz_dropobj(desc);
pdf_logfont("}\n");
return nil;
cleanup:
fz_dropobj(desc);
return error;
}
fz_error *
pdf_loadfont(pdf_font **fontp, pdf_xref *xref, fz_obj *dict, fz_obj *ref)
{
fz_error *error;
char *subtype;
if ((*fontp = pdf_finditem(xref->store, PDF_KFONT, ref)))
{
fz_keepfont((fz_font*)*fontp);
return nil;
}
subtype = fz_toname(fz_dictgets(dict, "Subtype"));
if (!strcmp(subtype, "Type0"))
error = loadtype0(fontp, xref, dict, ref);
else if (!strcmp(subtype, "Type1") || !strcmp(subtype, "MMType1"))
error = loadsimplefont(fontp, xref, dict, ref);
else if (!strcmp(subtype, "TrueType"))
error = loadsimplefont(fontp, xref, dict, ref);
else if (!strcmp(subtype, "Type3"))
error = pdf_loadtype3font(fontp, xref, dict, ref);
else
error = fz_throw("unimplemented: %s fonts", subtype);
if (error)
return error;
error = pdf_storeitem(xref->store, PDF_KFONT, ref, *fontp);
if (error)
return error;
return nil;
}