Ejemplo n.º 1
0
Archivo: path.c Proyecto: haggl/mupdf
fz_stroke_state *
fz_unshare_stroke_state_with_len(fz_context *ctx, fz_stroke_state *shared, int len)
{
    int single, unsize, shsize, shlen, drop;
    fz_stroke_state *unshared;

    fz_lock(ctx, FZ_LOCK_ALLOC);
    single = (shared->refs == 1);
    fz_unlock(ctx, FZ_LOCK_ALLOC);

    shlen = shared->dash_len - nelem(shared->dash_list);
    if (shlen < 0)
        shlen = 0;
    shsize = sizeof(*shared) + sizeof(shared->dash_list[0]) * shlen;
    len -= nelem(shared->dash_list);
    if (len < 0)
        len = 0;
    if (single && shlen >= len)
        return shared;
    unsize = sizeof(*unshared) + sizeof(unshared->dash_list[0]) * len;
    unshared = Memento_label(fz_malloc(ctx, unsize), "fz_stroke_state");
    memcpy(unshared, shared, (shsize > unsize ? unsize : shsize));
    unshared->refs = 1;
    fz_lock(ctx, FZ_LOCK_ALLOC);
    drop = (shared->refs > 0 ? --shared->refs == 0 : 0);
    fz_unlock(ctx, FZ_LOCK_ALLOC);
    if (drop)
        fz_free(ctx, shared);
    return unshared;
}
Ejemplo n.º 2
0
fz_font *
fz_new_font_from_memory(fz_context *ctx, char *name, unsigned char *data, int len, int index, int use_glyph_bbox)
{
	FT_Face face;
	fz_font *font;
	int fterr;

	fz_keep_freetype(ctx);

	fz_lock(ctx, FZ_LOCK_FREETYPE);
	fterr = FT_New_Memory_Face(ctx->font->ftlib, data, len, index, &face);
	fz_unlock(ctx, FZ_LOCK_FREETYPE);
	if (fterr)
	{
		fz_drop_freetype(ctx);
		fz_throw(ctx, FZ_ERROR_GENERIC, "freetype: cannot load font: %s", ft_error_string(fterr));
	}

	if (!name)
		name = face->family_name;

	font = fz_new_font(ctx, name, use_glyph_bbox, face->num_glyphs);
	font->ft_face = face;
	fz_set_font_bbox(ctx, font,
		(float) face->bbox.xMin / face->units_per_EM,
		(float) face->bbox.yMin / face->units_per_EM,
		(float) face->bbox.xMax / face->units_per_EM,
		(float) face->bbox.yMax / face->units_per_EM);

	return font;
}
Ejemplo n.º 3
0
Archivo: context.c Proyecto: jogu/mupdf
void fz_set_user_css(fz_context *ctx, const char *user_css)
{
	fz_lock(ctx, FZ_LOCK_ALLOC);
	fz_free(ctx, ctx->style->user_css);
	ctx->style->user_css = fz_strdup(ctx, user_css);
	fz_unlock(ctx, FZ_LOCK_ALLOC);
}
Ejemplo n.º 4
0
void
fz_free(fz_context *ctx, void *p)
{
	fz_lock(ctx, FZ_LOCK_ALLOC);
	ctx->alloc->free(ctx->alloc->user, p);
	fz_unlock(ctx, FZ_LOCK_ALLOC);
}
Ejemplo n.º 5
0
fz_font *
fz_new_font_from_file(fz_context *ctx, char *name, char *path, int index, int use_glyph_bbox)
{
	FT_Face face;
	fz_font *font;
	int fterr;

	fz_keep_freetype(ctx);

	fz_lock(ctx, FZ_LOCK_FREETYPE);
	fterr = FT_New_Face(ctx->font->ftlib, path, index, &face);
	fz_unlock(ctx, FZ_LOCK_FREETYPE);
	if (fterr)
	{
		fz_drop_freetype(ctx);
		fz_throw(ctx, "freetype: cannot load font: %s", ft_error_string(fterr));
	}
	fz_check_font_dimensions(face);

	if (!name)
		name = face->family_name;

	font = fz_new_font(ctx, name, use_glyph_bbox, face->num_glyphs);
	font->ft_face = face;
	font->bbox.x0 = (float) face->bbox.xMin / face->units_per_EM;
	font->bbox.y0 = (float) face->bbox.yMin / face->units_per_EM;
	font->bbox.x1 = (float) face->bbox.xMax / face->units_per_EM;
	font->bbox.y1 = (float) face->bbox.yMax / face->units_per_EM;

	return font;
}
Ejemplo n.º 6
0
void
fz_purge_glyph_cache(fz_context *ctx)
{
	fz_lock(ctx, FZ_LOCK_GLYPHCACHE);
	do_purge(ctx);
	fz_unlock(ctx, FZ_LOCK_GLYPHCACHE);
}
Ejemplo n.º 7
0
static fz_matrix *
fz_adjust_ft_glyph_width(fz_context *ctx, fz_font *font, int gid, fz_matrix *trm)
{
	/* Fudge the font matrix to stretch the glyph if we've substituted the font. */
	if (font->ft_substitute && font->width_table && gid < font->width_count)
	{
		FT_Error fterr;
		int subw;
		int realw;
		float scale;

		fz_lock(ctx, FZ_LOCK_FREETYPE);
		/* TODO: use FT_Get_Advance */
		fterr = FT_Set_Char_Size(font->ft_face, 1000, 1000, 72, 72);
		if (fterr)
			fz_warn(ctx, "freetype setting character size: %s", ft_error_string(fterr));

		fterr = FT_Load_Glyph(font->ft_face, gid,
			FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM);
		if (fterr)
			fz_warn(ctx, "freetype failed to load glyph: %s", ft_error_string(fterr));

		realw = ((FT_Face)font->ft_face)->glyph->metrics.horiAdvance;
		fz_unlock(ctx, FZ_LOCK_FREETYPE);
		subw = font->width_table[gid];
		if (realw)
			scale = (float) subw / realw;
		else
			scale = 1;

		fz_pre_scale(trm, scale, 1);
	}

	return trm;
}
Ejemplo n.º 8
0
void
fz_set_device_lab(fz_context *ctx, fz_colorspace *cs)
{
	fz_lock(ctx, FZ_LOCK_ALLOC);
	fz_drop_colorspace(ctx, ctx->colorspace->lab);
	ctx->colorspace->lab = fz_keep_colorspace(ctx, cs);
	fz_unlock(ctx, FZ_LOCK_ALLOC);
}
Ejemplo n.º 9
0
fz_glyph_cache *
fz_keep_glyph_cache(fz_context *ctx)
{
	fz_lock(ctx, FZ_LOCK_GLYPHCACHE);
	ctx->glyph_cache->refs++;
	fz_unlock(ctx, FZ_LOCK_GLYPHCACHE);
	return ctx->glyph_cache;
}
Ejemplo n.º 10
0
void
fz_drop_font(fz_context *ctx, fz_font *font)
{
	int fterr;
	int i, drop;

	fz_lock(ctx, FZ_LOCK_ALLOC);
	drop = (font && --font->refs == 0);
	fz_unlock(ctx, FZ_LOCK_ALLOC);
	if (!drop)
		return;

	if (font->t3procs)
	{
		if (font->t3resources)
			font->t3freeres(font->t3doc, font->t3resources);
		for (i = 0; i < 256; i++)
		{
			if (font->t3procs[i])
				fz_drop_buffer(ctx, font->t3procs[i]);
			if (font->t3lists[i])
				fz_free_display_list(ctx, font->t3lists[i]);
		}
		fz_free(ctx, font->t3procs);
		fz_free(ctx, font->t3lists);
		fz_free(ctx, font->t3widths);
		fz_free(ctx, font->t3flags);
	}

	if (font->ft_face)
	{
		fz_lock(ctx, FZ_LOCK_FREETYPE);
		fterr = FT_Done_Face((FT_Face)font->ft_face);
		fz_unlock(ctx, FZ_LOCK_FREETYPE);
		if (fterr)
			fz_warn(ctx, "freetype finalizing face: %s", ft_error_string(fterr));
		fz_drop_freetype(ctx);
	}

	fz_free(ctx, font->ft_file);
	fz_free(ctx, font->ft_data);
	fz_free(ctx, font->bbox_table);
	fz_free(ctx, font->width_table);
	fz_free(ctx, font);
}
Ejemplo n.º 11
0
void
fz_lock_stream(fz_stream *stm)
{
	if (stm)
	{
		fz_lock(stm->ctx, FZ_LOCK_FILE);
		stm->locked = 1;
	}
}
Ejemplo n.º 12
0
fz_font_context *
fz_keep_font_context(fz_context *ctx)
{
	if (!ctx || !ctx->font)
		return NULL;
	fz_lock(ctx, FZ_LOCK_ALLOC);
	ctx->font->ctx_refs++;
	fz_unlock(ctx, FZ_LOCK_ALLOC);
	return ctx->font;
}
Ejemplo n.º 13
0
fz_font *
fz_keep_font(fz_context *ctx, fz_font *font)
{
	if (!font)
		return NULL;
	fz_lock(ctx, FZ_LOCK_ALLOC);
	font->refs ++;
	fz_unlock(ctx, FZ_LOCK_ALLOC);
	return font;
}
Ejemplo n.º 14
0
static void *
pdf_keep_image_key(fz_context *ctx, void *key_)
{
	pdf_image_key *key = (pdf_image_key *)key_;

	fz_lock(ctx, FZ_LOCK_ALLOC);
	key->refs++;
	fz_unlock(ctx, FZ_LOCK_ALLOC);

	return (void *)key;
}
Ejemplo n.º 15
0
void fz_drop_font_context(fz_context *ctx)
{
	int drop;
	if (!ctx || !ctx->font)
		return;
	fz_lock(ctx, FZ_LOCK_ALLOC);
	drop = --ctx->font->ctx_refs;
	fz_unlock(ctx, FZ_LOCK_ALLOC);
	if (drop == 0)
		fz_free(ctx, ctx->font);
}
Ejemplo n.º 16
0
Archivo: path.c Proyecto: haggl/mupdf
fz_stroke_state *
fz_keep_stroke_state(fz_context *ctx, fz_stroke_state *stroke)
{
    if (!stroke)
        return NULL;

    fz_lock(ctx, FZ_LOCK_ALLOC);
    if (stroke->refs > 0)
        stroke->refs++;
    fz_unlock(ctx, FZ_LOCK_ALLOC);
    return stroke;
}
Ejemplo n.º 17
0
int
fz_gen_id(fz_context *ctx)
{
	int id;
	fz_lock(ctx, FZ_LOCK_ALLOC);
	/* We'll never wrap around in normal use, but if we do, then avoid 0. */
	do
		id = ++ctx->id->id;
	while (id == 0);
	fz_unlock(ctx, FZ_LOCK_ALLOC);
	return id;
}
Ejemplo n.º 18
0
static fz_id_context *
fz_keep_id_context(fz_context *ctx)
{
	fz_id_context *id = ctx->id;

	if (id == NULL)
		return NULL;
	fz_lock(ctx, FZ_LOCK_ALLOC);
	++id->refs;
	fz_unlock(ctx, FZ_LOCK_ALLOC);
	return id;
}
Ejemplo n.º 19
0
Archivo: path.c Proyecto: haggl/mupdf
void
fz_drop_stroke_state(fz_context *ctx, fz_stroke_state *stroke)
{
    int drop;

    if (!stroke)
        return;

    fz_lock(ctx, FZ_LOCK_ALLOC);
    drop = (stroke->refs > 0 ? --stroke->refs == 0 : 0);
    fz_unlock(ctx, FZ_LOCK_ALLOC);
    if (drop)
        fz_free(ctx, stroke);
}
Ejemplo n.º 20
0
static void
fz_drop_id_context(fz_context *ctx)
{
	int refs;
	fz_id_context *id = ctx->id;

	if (id == NULL)
		return;
	fz_lock(ctx, FZ_LOCK_ALLOC);
	refs = --id->refs;
	fz_unlock(ctx, FZ_LOCK_ALLOC);
	if (refs == 0)
		fz_free(ctx, id);
}
Ejemplo n.º 21
0
fz_separations *fz_keep_separations(fz_context *ctx, fz_separations *sep)
{
	int i;

	if (!ctx || !sep)
		return NULL;

	fz_lock(ctx, FZ_LOCK_ALLOC);
	i = sep->refs;
	if (i > 0)
		sep->refs++;
	fz_unlock(ctx, FZ_LOCK_ALLOC);

	return sep;
}
Ejemplo n.º 22
0
void fz_drop_separations(fz_context *ctx, fz_separations *sep)
{
	int i;

	if (!ctx || !sep)
		return;

	fz_lock(ctx, FZ_LOCK_ALLOC);
	i = sep->refs;
	if (i > 0)
		sep->refs--;
	fz_unlock(ctx, FZ_LOCK_ALLOC);
	if (i == 1)
		fz_free(ctx, sep);
}
Ejemplo n.º 23
0
static void
pdf_drop_image_key(fz_context *ctx, void *key_)
{
	pdf_image_key *key = (pdf_image_key *)key_;
	int drop;

	fz_lock(ctx, FZ_LOCK_ALLOC);
	drop = --key->refs;
	fz_unlock(ctx, FZ_LOCK_ALLOC);
	if (drop == 0)
	{
		fz_drop_image(ctx, key->image);
		fz_free(ctx, key);
	}
}
Ejemplo n.º 24
0
void
xps_measure_font_glyph(fz_context *ctx, xps_document *doc, fz_font *font, int gid, xps_glyph_metrics *mtx)
{
    int mask = FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM;
    FT_Face face = font->ft_face;
    FT_Fixed hadv = 0, vadv = 0;

    fz_lock(ctx, FZ_LOCK_FREETYPE);
    FT_Get_Advance(face, gid, mask, &hadv);
    FT_Get_Advance(face, gid, mask | FT_LOAD_VERTICAL_LAYOUT, &vadv);
    fz_unlock(ctx, FZ_LOCK_FREETYPE);

    mtx->hadv = hadv / (float)face->units_per_EM;
    mtx->vadv = vadv / (float)face->units_per_EM;
    mtx->vorg = face->ascender / (float) face->units_per_EM;
}
Ejemplo n.º 25
0
static void
fz_drop_freetype(fz_context *ctx)
{
	int fterr;
	fz_font_context *fct = ctx->font;

	fz_lock(ctx, FZ_LOCK_FREETYPE);
	if (--fct->ftlib_refs == 0)
	{
		fterr = FT_Done_FreeType(fct->ftlib);
		if (fterr)
			fz_warn(ctx, "freetype finalizing: %s", ft_error_string(fterr));
		fct->ftlib = NULL;
	}
	fz_unlock(ctx, FZ_LOCK_FREETYPE);
}
Ejemplo n.º 26
0
void
fz_drop_glyph_cache_context(fz_context *ctx)
{
	if (!ctx->glyph_cache)
		return;

	fz_lock(ctx, FZ_LOCK_GLYPHCACHE);
	ctx->glyph_cache->refs--;
	if (ctx->glyph_cache->refs == 0)
	{
		do_purge(ctx);
		fz_free(ctx, ctx->glyph_cache);
		ctx->glyph_cache = NULL;
	}
	fz_unlock(ctx, FZ_LOCK_GLYPHCACHE);
}
Ejemplo n.º 27
0
static void *
do_scavenging_realloc(fz_context *ctx, void *p, unsigned int size)
{
	void *q;
	int phase = 0;

	fz_lock(ctx, FZ_LOCK_ALLOC);
	do {
		q = ctx->alloc->realloc(ctx->alloc->user, p, size);
		if (q != NULL)
		{
			fz_unlock(ctx, FZ_LOCK_ALLOC);
			return q;
		}
	} while (fz_store_scavenge(ctx, size, &phase));
	fz_unlock(ctx, FZ_LOCK_ALLOC);

	return NULL;
}
Ejemplo n.º 28
0
static void *
do_scavenging_malloc(fz_context *ctx, unsigned int size)
{
	void *p;
	int phase = 0;

	fz_lock(ctx, FZ_LOCK_ALLOC);
	do {
		p = ctx->alloc->malloc(ctx->alloc->user, size);
		if (p != NULL)
		{
			fz_unlock(ctx, FZ_LOCK_ALLOC);
			return p;
		}
	} while (fz_store_scavenge(ctx, size, &phase));
	fz_unlock(ctx, FZ_LOCK_ALLOC);

	return NULL;
}
Ejemplo n.º 29
0
static void
fz_keep_freetype(fz_context *ctx)
{
	int fterr;
	int maj, min, pat;
	fz_font_context *fct = ctx->font;

	fz_lock(ctx, FZ_LOCK_FREETYPE);
	if (fct->ftlib)
	{
		fct->ftlib_refs++;
		fz_unlock(ctx, FZ_LOCK_FREETYPE);
		return;
	}

	fterr = FT_Init_FreeType(&fct->ftlib);
	if (fterr)
	{
		char *mess = ft_error_string(fterr);
		fz_unlock(ctx, FZ_LOCK_FREETYPE);
		fz_throw(ctx, FZ_ERROR_GENERIC, "cannot init freetype: %s", mess);
	}

	FT_Library_Version(fct->ftlib, &maj, &min, &pat);
	if (maj == 2 && min == 1 && pat < 7)
	{
		fterr = FT_Done_FreeType(fct->ftlib);
		if (fterr)
			fz_warn(ctx, "freetype finalizing: %s", ft_error_string(fterr));
		fz_unlock(ctx, FZ_LOCK_FREETYPE);
		fz_throw(ctx, FZ_ERROR_GENERIC, "freetype version too old: %d.%d.%d", maj, min, pat);
	}

	fct->ftlib_refs++;
	fz_unlock(ctx, FZ_LOCK_FREETYPE);
}
Ejemplo n.º 30
0
static pdf_font_desc *
pdf_load_simple_font(pdf_document *xref, pdf_obj *dict)
{
	pdf_obj *descriptor;
	pdf_obj *encoding;
	pdf_obj *widths;
	unsigned short *etable = NULL;
	pdf_font_desc *fontdesc = NULL;
	char *subtype;
	FT_Face face;
	FT_CharMap cmap;
	int symbolic;
	int kind;

	char *basefont;
	char *estrings[256];
	char ebuffer[256][32];
	int i, k, n;
	int fterr;
	fz_context *ctx = xref->ctx;

	fz_var(fontdesc);
	fz_var(etable);

	basefont = pdf_to_name(pdf_dict_gets(dict, "BaseFont"));

	/* Load font file */
	fz_try(ctx)
	{
		fontdesc = pdf_new_font_desc(ctx);

		descriptor = pdf_dict_gets(dict, "FontDescriptor");
		if (descriptor)
			pdf_load_font_descriptor(fontdesc, xref, descriptor, NULL, basefont);
		else
			pdf_load_builtin_font(ctx, fontdesc, basefont);

		/* Some chinese documents mistakenly consider WinAnsiEncoding to be codepage 936 */
		if (descriptor && pdf_is_string(pdf_dict_gets(descriptor, "FontName")) &&
			!pdf_dict_gets(dict, "ToUnicode") &&
			!strcmp(pdf_to_name(pdf_dict_gets(dict, "Encoding")), "WinAnsiEncoding") &&
			pdf_to_int(pdf_dict_gets(descriptor, "Flags")) == 4)
		{
			char *cp936fonts[] = {
				"\xCB\xCE\xCC\xE5", "SimSun,Regular",
				"\xBA\xDA\xCC\xE5", "SimHei,Regular",
				"\xBF\xAC\xCC\xE5_GB2312", "SimKai,Regular",
				"\xB7\xC2\xCB\xCE_GB2312", "SimFang,Regular",
				"\xC1\xA5\xCA\xE9", "SimLi,Regular",
				NULL
			};
			for (i = 0; cp936fonts[i]; i += 2)
				if (!strcmp(basefont, cp936fonts[i]))
					break;
			if (cp936fonts[i])
			{
				fz_warn(ctx, "workaround for S22PDF lying about chinese font encodings");
				pdf_drop_font(ctx, fontdesc);
				fontdesc = pdf_new_font_desc(ctx);
				pdf_load_font_descriptor(fontdesc, xref, descriptor, "Adobe-GB1", cp936fonts[i+1]);
				fontdesc->encoding = pdf_load_system_cmap(ctx, "GBK-EUC-H");
				fontdesc->to_unicode = pdf_load_system_cmap(ctx, "Adobe-GB1-UCS2");
				fontdesc->to_ttf_cmap = pdf_load_system_cmap(ctx, "Adobe-GB1-UCS2");

				face = fontdesc->font->ft_face;
				kind = ft_kind(face);
				goto skip_encoding;
			}
		}

		face = fontdesc->font->ft_face;
		kind = ft_kind(face);

		/* Encoding */

		symbolic = fontdesc->flags & 4;

		if (face->num_charmaps > 0)
			cmap = face->charmaps[0];
		else
			cmap = NULL;

		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 (symbolic && test->platform_id == 3 && test->encoding_id == 0)
					cmap = test;
			}
		}

		if (cmap)
		{
			fterr = FT_Set_Charmap(face, cmap);
			if (fterr)
				fz_warn(ctx, "freetype could not set cmap: %s", ft_error_string(fterr));
		}
		else
			fz_warn(ctx, "freetype could not find any cmaps");

		etable = fz_malloc_array(ctx, 256, sizeof(unsigned short));
		fontdesc->size += 256 * sizeof(unsigned short);
		for (i = 0; i < 256; i++)
		{
			estrings[i] = NULL;
			etable[i] = 0;
		}

		encoding = pdf_dict_gets(dict, "Encoding");
		if (encoding)
		{
			if (pdf_is_name(encoding))
				pdf_load_encoding(estrings, pdf_to_name(encoding));

			if (pdf_is_dict(encoding))
			{
				pdf_obj *base, *diff, *item;

				base = pdf_dict_gets(encoding, "BaseEncoding");
				if (pdf_is_name(base))
					pdf_load_encoding(estrings, pdf_to_name(base));
				else if (!fontdesc->is_embedded && !symbolic)
					pdf_load_encoding(estrings, "StandardEncoding");

				diff = pdf_dict_gets(encoding, "Differences");
				if (pdf_is_array(diff))
				{
					n = pdf_array_len(diff);
					k = 0;
					for (i = 0; i < n; i++)
					{
						item = pdf_array_get(diff, i);
						if (pdf_is_int(item))
							k = pdf_to_int(item);
						if (pdf_is_name(item) && k >= 0 && k < nelem(estrings))
							estrings[k++] = pdf_to_name(item);
					}
				}
			}
		}

		/* start with the builtin encoding */
		for (i = 0; i < 256; i++)
			etable[i] = ft_char_index(face, i);

		fz_lock(ctx, FZ_LOCK_FREETYPE);

		/* built-in and substitute fonts may be a different type than what the document expects */
		subtype = pdf_to_name(pdf_dict_gets(dict, "Subtype"));
		if (!strcmp(subtype, "Type1"))
			kind = TYPE1;
		else if (!strcmp(subtype, "MMType1"))
			kind = TYPE1;
		else if (!strcmp(subtype, "TrueType"))
			kind = TRUETYPE;
		else if (!strcmp(subtype, "CIDFontType0"))
			kind = TYPE1;
		else if (!strcmp(subtype, "CIDFontType2"))
			kind = TRUETYPE;

		/* encode by glyph name where we can */
		if (kind == TYPE1)
		{
			for (i = 0; i < 256; i++)
			{
				if (estrings[i])
				{
					etable[i] = FT_Get_Name_Index(face, estrings[i]);
					if (etable[i] == 0)
					{
						int aglcode = pdf_lookup_agl(estrings[i]);
						const char **dupnames = pdf_lookup_agl_duplicates(aglcode);
						while (*dupnames)
						{
							etable[i] = FT_Get_Name_Index(face, (char*)*dupnames);
							if (etable[i])
								break;
							dupnames++;
						}
					}
				}
			}
		}

		/* encode by glyph name where we can */
		if (kind == TRUETYPE)
		{
			/* Unicode cmap */
			if (!symbolic && face->charmap && face->charmap->platform_id == 3)
			{
				for (i = 0; i < 256; i++)
				{
					if (estrings[i])
					{
						int aglcode = pdf_lookup_agl(estrings[i]);
						if (!aglcode)
							etable[i] = FT_Get_Name_Index(face, estrings[i]);
						else
							etable[i] = ft_char_index(face, aglcode);
					}
				}
			}

			/* MacRoman cmap */
			else if (!symbolic && face->charmap && face->charmap->platform_id == 1)
			{
				for (i = 0; i < 256; i++)
				{
					if (estrings[i])
					{
						k = lookup_mre_code(estrings[i]);
						if (k <= 0)
							etable[i] = FT_Get_Name_Index(face, estrings[i]);
						else
							etable[i] = ft_char_index(face, k);
					}
				}
			}

			/* Symbolic cmap */
			else if (!face->charmap || face->charmap->encoding != FT_ENCODING_MS_SYMBOL)
			{
				for (i = 0; i < 256; i++)
				{
					if (estrings[i])
					{
						etable[i] = FT_Get_Name_Index(face, estrings[i]);
						if (etable[i] == 0)
							etable[i] = ft_char_index(face, i);
					}
				}
			}
		}

		/* try to reverse the glyph names from the builtin encoding */
		for (i = 0; i < 256; i++)
		{
			if (etable[i] && !estrings[i])
			{
				if (FT_HAS_GLYPH_NAMES(face))
				{
					fterr = FT_Get_Glyph_Name(face, etable[i], ebuffer[i], 32);
					if (fterr)
						fz_warn(ctx, "freetype get glyph name (gid %d): %s", etable[i], ft_error_string(fterr));
					if (ebuffer[i][0])
						estrings[i] = ebuffer[i];
				}
				else
				{
					estrings[i] = (char*) pdf_win_ansi[i]; /* discard const */
				}
			}
		}

		/* symbolic Type 1 fonts with an implicit encoding and non-standard glyph names */
		if (kind == TYPE1 && symbolic)
		{
			for (i = 0; i < 256; i++)
				if (etable[i] && estrings[i] && !pdf_lookup_agl(estrings[i]))
					estrings[i] = (char*) pdf_standard[i];
		}

		fz_unlock(ctx, FZ_LOCK_FREETYPE);

		fontdesc->encoding = pdf_new_identity_cmap(ctx, 0, 1);
		fontdesc->size += pdf_cmap_size(ctx, fontdesc->encoding);
		fontdesc->cid_to_gid_len = 256;
		fontdesc->cid_to_gid = etable;

		fz_try(ctx)
		{
			pdf_load_to_unicode(xref, fontdesc, estrings, NULL, pdf_dict_gets(dict, "ToUnicode"));
		}
		fz_catch(ctx)
		{
			fz_warn(ctx, "cannot load ToUnicode CMap");
		}

	skip_encoding:

		/* Widths */

		pdf_set_default_hmtx(ctx, fontdesc, fontdesc->missing_width);

		widths = pdf_dict_gets(dict, "Widths");
		if (widths)
		{
			int first, last;

			first = pdf_to_int(pdf_dict_gets(dict, "FirstChar"));
			last = pdf_to_int(pdf_dict_gets(dict, "LastChar"));

			if (first < 0 || last > 255 || first > last)
				first = last = 0;

			for (i = 0; i < last - first + 1; i++)
			{
				int wid = pdf_to_int(pdf_array_get(widths, i));
				pdf_add_hmtx(ctx, fontdesc, i + first, i + first, wid);
			}
		}
		else
		{
			fz_lock(ctx, FZ_LOCK_FREETYPE);
			fterr = FT_Set_Char_Size(face, 1000, 1000, 72, 72);
			if (fterr)
				fz_warn(ctx, "freetype set character size: %s", ft_error_string(fterr));
			for (i = 0; i < 256; i++)
			{
				pdf_add_hmtx(ctx, fontdesc, i, i, ft_width(ctx, fontdesc, i));
			}
			fz_unlock(ctx, FZ_LOCK_FREETYPE);
		}

		pdf_end_hmtx(ctx, fontdesc);
	}
	fz_catch(ctx)
	{
		if (fontdesc && etable != fontdesc->cid_to_gid)
			fz_free(ctx, etable);
		pdf_drop_font(ctx, fontdesc);
		fz_throw(ctx, "cannot load simple font (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict));
	}
	return fontdesc;
}