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; }
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; }
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); }
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); }
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; }
void fz_purge_glyph_cache(fz_context *ctx) { fz_lock(ctx, FZ_LOCK_GLYPHCACHE); do_purge(ctx); fz_unlock(ctx, FZ_LOCK_GLYPHCACHE); }
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; }
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); }
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; }
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); }
void fz_lock_stream(fz_stream *stm) { if (stm) { fz_lock(stm->ctx, FZ_LOCK_FILE); stm->locked = 1; } }
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; }
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; }
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; }
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); }
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; }
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; }
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; }
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); }
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); }
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; }
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); }
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); } }
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; }
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); }
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); }
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; }
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; }
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); }
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; }