static void fz_add_text_char(fz_context *ctx, fz_text_span **last, fz_font *font, float size, int wmode, int c, fz_bbox bbox) { fz_text_span *span = *last; if (!span->font) { span->font = fz_keep_font(ctx, font); span->size = size; } if ((span->font != font || span->size != size || span->wmode != wmode) && c != 32) { span = fz_new_text_span(ctx); span->font = fz_keep_font(ctx, font); span->size = size; span->wmode = wmode; (*last)->next = span; *last = span; } switch (c) { case -1: /* ignore when one unicode character maps to multiple glyphs */ break; case 0xFB00: /* ff */ fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 0, 2)); fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 1, 2)); break; case 0xFB01: /* fi */ fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 0, 2)); fz_add_text_char_imp(ctx, span, 'i', fz_split_bbox(bbox, 1, 2)); break; case 0xFB02: /* fl */ fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 0, 2)); fz_add_text_char_imp(ctx, span, 'l', fz_split_bbox(bbox, 1, 2)); break; case 0xFB03: /* ffi */ fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 0, 3)); fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 1, 3)); fz_add_text_char_imp(ctx, span, 'i', fz_split_bbox(bbox, 2, 3)); break; case 0xFB04: /* ffl */ fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 0, 3)); fz_add_text_char_imp(ctx, span, 'f', fz_split_bbox(bbox, 1, 3)); fz_add_text_char_imp(ctx, span, 'l', fz_split_bbox(bbox, 2, 3)); break; case 0xFB05: /* long st */ case 0xFB06: /* st */ fz_add_text_char_imp(ctx, span, 's', fz_split_bbox(bbox, 0, 2)); fz_add_text_char_imp(ctx, span, 't', fz_split_bbox(bbox, 1, 2)); break; default: fz_add_text_char_imp(ctx, span, c, bbox); break; } }
static fz_text_style * fz_lookup_text_style_imp(fz_context *ctx, fz_text_sheet *sheet, float size, fz_font *font, int wmode, int script) { fz_text_style *style; for (style = sheet->style; style; style = style->next) { if (style->font == font && style->size == size && style->wmode == wmode && style->script == script) /* FIXME: others */ { return style; } } /* Better make a new one and add it to our list */ style = fz_malloc(ctx, sizeof *style); style->id = sheet->maxid++; style->font = fz_keep_font(ctx, font); style->size = size; style->wmode = wmode; style->script = script; style->next = sheet->style; sheet->style = style; return style; }
static void xps_insert_font(fz_context *ctx, xps_document *doc, char *name, fz_font *font) { xps_font_cache *cache = fz_malloc_struct(ctx, xps_font_cache); cache->name = fz_strdup(ctx, name); cache->font = fz_keep_font(ctx, font); cache->next = doc->font_table; doc->font_table = cache; }
static fz_font * xps_lookup_font_imp(fz_context *ctx, xps_document *doc, char *name) { xps_font_cache *cache; for (cache = doc->font_table; cache; cache = cache->next) if (!xps_strcasecmp(cache->name, name)) return fz_keep_font(ctx, cache->font); return NULL; }
static fz_text_span * fz_new_text_span(fz_context *ctx, fz_font *font, int wmode, const fz_matrix *trm) { fz_text_span *span = fz_malloc_struct(ctx, fz_text_span); span->font = fz_keep_font(ctx, font); span->wmode = wmode; span->trm = *trm; span->trm.e = 0; span->trm.f = 0; return span; }
static void fz_add_text_newline(fz_context *ctx, fz_text_span **last, fz_font *font, float size, int wmode) { fz_text_span *span; span = fz_new_text_span(ctx); span->font = fz_keep_font(ctx, font); span->size = size; span->wmode = wmode; (*last)->eol = 1; (*last)->next = span; *last = span; }
fz_text * fz_clone_text(fz_context *ctx, const fz_text *text) { fz_text *new_text; fz_text_span *span; fz_text_span **tail; new_text = fz_malloc_struct(ctx, fz_text); new_text->refs = 1; span = text->head; tail = &new_text->head; fz_var(span); fz_try(ctx) { while (span != NULL) { fz_text_span *new_span = fz_malloc_struct(ctx, fz_text_span); *tail = new_span; tail = &new_span->next; new_text->tail = new_span; new_span->font = fz_keep_font(ctx, span->font); new_span->trm = span->trm; new_span->wmode = span->wmode; new_span->len = span->len; new_span->cap = span->len; new_span->items = fz_malloc(ctx, span->len * sizeof(*span->items)); memcpy(new_span->items, span->items, span->len * sizeof(*span->items)); span = span->next; } } fz_catch(ctx) { span = new_text->head; while (span != NULL) { fz_text_span *next = span->next; fz_drop_font(ctx, span->font); fz_free(ctx, span->items); fz_free(ctx, span); span = next; } fz_free(ctx, new_text); fz_rethrow(ctx); } return new_text; }
fz_text * fz_new_text(fz_context *ctx, fz_font *font, fz_matrix trm, int wmode) { fz_text *text; text = fz_malloc_struct(ctx, fz_text); text->font = fz_keep_font(ctx, font); text->trm = trm; text->wmode = wmode; text->len = 0; text->cap = 0; text->items = NULL; return text; }
fz_text * fz_clone_text(fz_context *ctx, fz_text *old) { fz_text *text; text = fz_malloc_struct(ctx, fz_text); text->len = old->len; fz_try(ctx) { text->items = fz_malloc_array(ctx, text->len, sizeof(fz_text_item)); } fz_catch(ctx) { fz_free(ctx, text); fz_rethrow(ctx); } memcpy(text->items, old->items, text->len * sizeof(fz_text_item)); text->font = fz_keep_font(ctx, old->font); text->trm = old->trm; text->wmode = old->wmode; text->cap = text->len; return text; }
pdf_font_desc * pdf_load_type3_font(fz_context *ctx, pdf_document *doc, pdf_obj *rdb, pdf_obj *dict) { char buf[256]; char *estrings[256]; pdf_font_desc *fontdesc = NULL; pdf_obj *encoding; pdf_obj *widths; pdf_obj *charprocs; pdf_obj *obj; int first, last; int i, k, n; fz_rect bbox; fz_matrix matrix; fz_font *font; fz_var(fontdesc); /* Make a new type3 font entry in the document */ if (doc->num_type3_fonts == doc->max_type3_fonts) { int new_max = doc->max_type3_fonts * 2; if (new_max == 0) new_max = 4; doc->type3_fonts = fz_resize_array(ctx, doc->type3_fonts, new_max, sizeof(*doc->type3_fonts)); doc->max_type3_fonts = new_max; } fz_try(ctx) { obj = pdf_dict_get(ctx, dict, PDF_NAME_Name); if (pdf_is_name(ctx, obj)) fz_strlcpy(buf, pdf_to_name(ctx, obj), sizeof buf); else fz_strlcpy(buf, "Unnamed-T3", sizeof buf); fontdesc = pdf_new_font_desc(ctx); obj = pdf_dict_get(ctx, dict, PDF_NAME_FontMatrix); pdf_to_matrix(ctx, obj, &matrix); obj = pdf_dict_get(ctx, dict, PDF_NAME_FontBBox); fz_transform_rect(pdf_to_rect(ctx, obj, &bbox), &matrix); font = fz_new_type3_font(ctx, buf, &matrix); fontdesc->font = font; fontdesc->size += sizeof(fz_font) + 256 * (sizeof(fz_buffer*) + sizeof(float)); fz_set_font_bbox(ctx, font, bbox.x0, bbox.y0, bbox.x1, bbox.y1); /* Encoding */ for (i = 0; i < 256; i++) estrings[i] = NULL; encoding = pdf_dict_get(ctx, dict, PDF_NAME_Encoding); if (!encoding) { fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: Type3 font missing Encoding"); } if (pdf_is_name(ctx, encoding)) pdf_load_encoding(estrings, pdf_to_name(ctx, encoding)); if (pdf_is_dict(ctx, encoding)) { pdf_obj *base, *diff, *item; base = pdf_dict_get(ctx, encoding, PDF_NAME_BaseEncoding); if (pdf_is_name(ctx, base)) pdf_load_encoding(estrings, pdf_to_name(ctx, base)); diff = pdf_dict_get(ctx, encoding, PDF_NAME_Differences); if (pdf_is_array(ctx, diff)) { n = pdf_array_len(ctx, diff); k = 0; for (i = 0; i < n; i++) { item = pdf_array_get(ctx, diff, i); if (pdf_is_int(ctx, item)) k = pdf_to_int(ctx, item); if (pdf_is_name(ctx, item) && k >= 0 && k < nelem(estrings)) estrings[k++] = pdf_to_name(ctx, item); } } } fontdesc->encoding = pdf_new_identity_cmap(ctx, 0, 1); fontdesc->size += pdf_cmap_size(ctx, fontdesc->encoding); pdf_load_to_unicode(ctx, doc, fontdesc, estrings, NULL, pdf_dict_get(ctx, dict, PDF_NAME_ToUnicode)); /* Widths */ pdf_set_default_hmtx(ctx, fontdesc, 0); first = pdf_to_int(ctx, pdf_dict_get(ctx, dict, PDF_NAME_FirstChar)); last = pdf_to_int(ctx, pdf_dict_get(ctx, dict, PDF_NAME_LastChar)); if (first < 0 || last > 255 || first > last) first = last = 0; widths = pdf_dict_get(ctx, dict, PDF_NAME_Widths); if (!widths) { fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: Type3 font missing Widths"); } for (i = first; i <= last; i++) { float w = pdf_to_real(ctx, pdf_array_get(ctx, widths, i - first)); w = font->t3matrix.a * w * 1000; font->t3widths[i] = w * 0.001f; pdf_add_hmtx(ctx, fontdesc, i, i, w); } pdf_end_hmtx(ctx, fontdesc); /* Resources -- inherit page resources if the font doesn't have its own */ font->t3freeres = pdf_t3_free_resources; font->t3resources = pdf_dict_get(ctx, dict, PDF_NAME_Resources); if (!font->t3resources) font->t3resources = rdb; if (font->t3resources) pdf_keep_obj(ctx, font->t3resources); if (!font->t3resources) fz_warn(ctx, "no resource dictionary for type 3 font!"); font->t3doc = doc; font->t3run = pdf_run_glyph_func; /* CharProcs */ charprocs = pdf_dict_get(ctx, dict, PDF_NAME_CharProcs); if (!charprocs) { fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: Type3 font missing CharProcs"); } for (i = 0; i < 256; i++) { if (estrings[i]) { obj = pdf_dict_gets(ctx, charprocs, estrings[i]); if (pdf_is_stream(ctx, obj)) { font->t3procs[i] = pdf_load_stream(ctx, obj); fz_trim_buffer(ctx, font->t3procs[i]); fontdesc->size += fz_buffer_storage(ctx, font->t3procs[i], NULL); fontdesc->size += 0; // TODO: display list size calculation } } } } fz_catch(ctx) { pdf_drop_font(ctx, fontdesc); fz_rethrow(ctx); } doc->type3_fonts[doc->num_type3_fonts++] = fz_keep_font(ctx, font); return fontdesc; }
fz_glyph * fz_render_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix *ctm, fz_colorspace *model, const fz_irect *scissor, int alpha) { fz_glyph_cache *cache; fz_glyph_key key; fz_matrix subpix_ctm; fz_irect subpix_scissor; float size; fz_glyph *val; int do_cache, locked, caching; fz_glyph_cache_entry *entry; unsigned hash; fz_var(locked); fz_var(caching); fz_var(val); memset(&key, 0, sizeof key); size = fz_subpixel_adjust(ctx, ctm, &subpix_ctm, &key.e, &key.f); if (size <= MAX_GLYPH_SIZE) { scissor = &fz_infinite_irect; do_cache = 1; } else { if (font->ft_face) return NULL; subpix_scissor.x0 = scissor->x0 - floorf(ctm->e); subpix_scissor.y0 = scissor->y0 - floorf(ctm->f); subpix_scissor.x1 = scissor->x1 - floorf(ctm->e); subpix_scissor.y1 = scissor->y1 - floorf(ctm->f); scissor = &subpix_scissor; do_cache = 0; } cache = ctx->glyph_cache; key.font = font; key.gid = gid; key.a = subpix_ctm.a * 65536; key.b = subpix_ctm.b * 65536; key.c = subpix_ctm.c * 65536; key.d = subpix_ctm.d * 65536; key.aa = fz_text_aa_level(ctx); hash = do_hash((unsigned char *)&key, sizeof(key)) % GLYPH_HASH_LEN; fz_lock(ctx, FZ_LOCK_GLYPHCACHE); entry = cache->entry[hash]; while (entry) { if (memcmp(&entry->key, &key, sizeof(key)) == 0) { move_to_front(cache, entry); val = fz_keep_glyph(ctx, entry->val); fz_unlock(ctx, FZ_LOCK_GLYPHCACHE); return val; } entry = entry->bucket_next; } locked = 1; caching = 0; val = NULL; fz_try(ctx) { if (font->ft_face) { val = fz_render_ft_glyph(ctx, font, gid, &subpix_ctm, key.aa); } else if (font->t3procs) { /* We drop the glyphcache here, and execute the t3 * glyph code. The danger here is that some other * thread will come along, and want the same glyph * too. If it does, we may both end up rendering * pixmaps. We cope with this later on, by ensuring * that only one gets inserted into the cache. If * we insert ours to find one already there, we * abandon ours, and use the one there already. */ fz_unlock(ctx, FZ_LOCK_GLYPHCACHE); locked = 0; val = fz_render_t3_glyph(ctx, font, gid, &subpix_ctm, model, scissor); fz_lock(ctx, FZ_LOCK_GLYPHCACHE); locked = 1; } else { fz_warn(ctx, "assert: uninitialized font structure"); } if (val && do_cache) { if (val->w < MAX_GLYPH_SIZE && val->h < MAX_GLYPH_SIZE) { /* If we throw an exception whilst caching, * just ignore the exception and carry on. */ caching = 1; if (!font->ft_face) { /* We had to unlock. Someone else might * have rendered in the meantime */ entry = cache->entry[hash]; while (entry) { if (memcmp(&entry->key, &key, sizeof(key)) == 0) { fz_drop_glyph(ctx, val); move_to_front(cache, entry); val = fz_keep_glyph(ctx, entry->val); goto unlock_and_return_val; } entry = entry->bucket_next; } } entry = fz_malloc_struct(ctx, fz_glyph_cache_entry); entry->key = key; entry->hash = hash; entry->bucket_next = cache->entry[hash]; if (entry->bucket_next) entry->bucket_next->bucket_prev = entry; cache->entry[hash] = entry; entry->val = fz_keep_glyph(ctx, val); fz_keep_font(ctx, key.font); entry->lru_next = cache->lru_head; if (entry->lru_next) entry->lru_next->lru_prev = entry; else cache->lru_tail = entry; cache->lru_head = entry; cache->total += fz_glyph_size(ctx, val); while (cache->total > MAX_CACHE_SIZE) { #ifndef NDEBUG cache->num_evictions++; cache->evicted += fz_glyph_size(ctx, cache->lru_tail->val); #endif drop_glyph_cache_entry(ctx, cache->lru_tail); } } } unlock_and_return_val: { } } fz_always(ctx) { if (locked) fz_unlock(ctx, FZ_LOCK_GLYPHCACHE); } fz_catch(ctx) { if (caching) fz_warn(ctx, "cannot encache glyph; continuing"); else fz_rethrow(ctx); } return val; }
static font * svg_dev_text_span_as_paths_defs(fz_context *ctx, fz_device *dev, fz_text_span *span, const fz_matrix *ctm) { svg_device *sdev = (svg_device*)dev; fz_output *out = sdev->out; int i, font_idx; font *fnt; fz_matrix shift = fz_identity; for (font_idx = 0; font_idx < sdev->num_fonts; font_idx++) { if (sdev->fonts[font_idx].font == span->font) break; } if (font_idx == sdev->num_fonts) { /* New font */ if (font_idx == sdev->max_fonts) { int newmax = sdev->max_fonts * 2; if (newmax == 0) newmax = 4; sdev->fonts = fz_resize_array(ctx, sdev->fonts, newmax, sizeof(*sdev->fonts)); memset(&sdev->fonts[font_idx], 0, (newmax - font_idx) * sizeof(sdev->fonts[0])); sdev->max_fonts = newmax; } sdev->fonts[font_idx].id = sdev->id++; sdev->fonts[font_idx].font = fz_keep_font(ctx, span->font); sdev->num_fonts++; } fnt = &sdev->fonts[font_idx]; for (i=0; i < span->len; i++) { fz_text_item *it = &span->items[i]; int gid = it->gid; if (gid < 0) continue; if (gid >= fnt->max_sentlist) { int j; fnt->sentlist = fz_resize_array(ctx, fnt->sentlist, gid+1, sizeof(fnt->sentlist[0])); for (j = fnt->max_sentlist; j <= gid; j++) { fnt->sentlist[j].x_off = FLT_MIN; fnt->sentlist[j].y_off = FLT_MIN; } fnt->max_sentlist = gid+1; } if (fnt->sentlist[gid].x_off == FLT_MIN) { /* Need to send this one */ fz_rect rect; fz_path *path; path = fz_outline_glyph(ctx, span->font, gid, &fz_identity); if (path) { fz_bound_path(ctx, path, NULL, &fz_identity, &rect); shift.e = -rect.x0; shift.f = -rect.y0; fz_transform_path(ctx, path, &shift); out = start_def(ctx, sdev); fz_printf(ctx, out, "<symbol id=\"font_%x_%x\">", fnt->id, gid); fz_printf(ctx, out, "<path"); svg_dev_path(ctx, sdev, path); fz_printf(ctx, out, "/>\n"); } else { fz_bound_glyph(ctx, span->font, gid, &fz_identity, &rect); shift.e = -rect.x0; shift.f = -rect.y0; out = start_def(ctx, sdev); fz_printf(ctx, out, "<symbol id=\"font_%x_%x\">", fnt->id, gid); fz_run_t3_glyph(ctx, span->font, gid, &shift, dev); } fz_printf(ctx, out, "</symbol>"); out = end_def(ctx, sdev); fnt->sentlist[gid].x_off = rect.x0; fnt->sentlist[gid].y_off = rect.y0; } } return fnt; }
pdf_font_desc * pdf_load_type3_font(pdf_document *doc, pdf_obj *rdb, pdf_obj *dict) { char buf[256]; char *estrings[256]; pdf_font_desc *fontdesc = NULL; pdf_obj *encoding; pdf_obj *widths; pdf_obj *charprocs; pdf_obj *obj; int first, last; int i, k, n; fz_rect bbox; fz_matrix matrix; fz_context *ctx = doc->ctx; fz_var(fontdesc); /* Make a new type3 font entry in the document */ if (doc->num_type3_fonts == doc->max_type3_fonts) { int new_max = doc->max_type3_fonts * 2; if (new_max == 0) new_max = 4; doc->type3_fonts = fz_resize_array(doc->ctx, doc->type3_fonts, new_max, sizeof(*doc->type3_fonts)); doc->max_type3_fonts = new_max; } fz_try(ctx) { obj = pdf_dict_gets(dict, "Name"); if (pdf_is_name(obj)) fz_strlcpy(buf, pdf_to_name(obj), sizeof buf); else sprintf(buf, "Unnamed-T3"); fontdesc = pdf_new_font_desc(ctx); obj = pdf_dict_gets(dict, "FontMatrix"); pdf_to_matrix(ctx, obj, &matrix); obj = pdf_dict_gets(dict, "FontBBox"); fz_transform_rect(pdf_to_rect(ctx, obj, &bbox), &matrix); fontdesc->font = fz_new_type3_font(ctx, buf, &matrix); fontdesc->size += sizeof(fz_font) + 256 * (sizeof(fz_buffer*) + sizeof(float)); fz_set_font_bbox(ctx, fontdesc->font, bbox.x0, bbox.y0, bbox.x1, bbox.y1); /* SumatraPDF: expose Type3 FontDescriptor flags */ fontdesc->flags = pdf_to_int(pdf_dict_gets(pdf_dict_gets(dict, "FontDescriptor"), "Flags")); /* Encoding */ for (i = 0; i < 256; i++) estrings[i] = NULL; encoding = pdf_dict_gets(dict, "Encoding"); if (!encoding) { fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: Type3 font missing 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)); 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); } } } fontdesc->encoding = pdf_new_identity_cmap(ctx, 0, 1); fontdesc->size += pdf_cmap_size(ctx, fontdesc->encoding); pdf_load_to_unicode(doc, fontdesc, estrings, NULL, pdf_dict_gets(dict, "ToUnicode")); /* SumatraPDF: trying to match Adobe Reader's behavior */ if (!(fontdesc->flags & PDF_FD_SYMBOLIC) && fontdesc->cid_to_ucs_len >= 128) for (i = 32; i < 128; i++) if (fontdesc->cid_to_ucs[i] == '?' || fontdesc->cid_to_ucs[i] == '\0') fontdesc->cid_to_ucs[i] = i; /* Widths */ pdf_set_default_hmtx(ctx, fontdesc, 0); first = pdf_to_int(pdf_dict_gets(dict, "FirstChar")); last = pdf_to_int(pdf_dict_gets(dict, "LastChar")); /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=1966 */ if (first >= 256 && last - first < 256) { fz_warn(ctx, "ignoring out-of-bound values for FirstChar/LastChar: %d/%d", first, last); last -= first; first = 0; } if (first < 0 || last > 255 || first > last) first = last = 0; widths = pdf_dict_gets(dict, "Widths"); if (!widths) { fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: Type3 font missing Widths"); } for (i = first; i <= last; i++) { float w = pdf_to_real(pdf_array_get(widths, i - first)); w = fontdesc->font->t3matrix.a * w * 1000; fontdesc->font->t3widths[i] = w * 0.001f; pdf_add_hmtx(ctx, fontdesc, i, i, w); } pdf_end_hmtx(ctx, fontdesc); /* Resources -- inherit page resources if the font doesn't have its own */ fontdesc->font->t3freeres = pdf_t3_free_resources; fontdesc->font->t3resources = pdf_dict_gets(dict, "Resources"); if (!fontdesc->font->t3resources) fontdesc->font->t3resources = rdb; if (fontdesc->font->t3resources) pdf_keep_obj(fontdesc->font->t3resources); if (!fontdesc->font->t3resources) fz_warn(ctx, "no resource dictionary for type 3 font!"); fontdesc->font->t3doc = doc; fontdesc->font->t3run = pdf_run_glyph_func; /* CharProcs */ charprocs = pdf_dict_gets(dict, "CharProcs"); if (!charprocs) { fz_throw(ctx, FZ_ERROR_GENERIC, "syntaxerror: Type3 font missing CharProcs"); } for (i = 0; i < 256; i++) { if (estrings[i]) { /* SumatraPDF: don't reject fonts with few broken glyphs */ fz_try(ctx) { obj = pdf_dict_gets(charprocs, estrings[i]); if (pdf_is_stream(doc, pdf_to_num(obj), pdf_to_gen(obj))) { fontdesc->font->t3procs[i] = pdf_load_stream(doc, pdf_to_num(obj), pdf_to_gen(obj)); fontdesc->size += fontdesc->font->t3procs[i]->cap; fontdesc->size += 0; // TODO: display list size calculation } } fz_catch(ctx) { fz_warn(ctx, "failed to get data for type 3 glyph '%s'", estrings[i]); } } } } fz_catch(ctx) { if (fontdesc) pdf_drop_font(ctx, fontdesc); fz_rethrow_message(ctx, "cannot load type3 font (%d %d R)", pdf_to_num(dict), pdf_to_gen(dict)); } doc->type3_fonts[doc->num_type3_fonts++] = fz_keep_font(ctx, fontdesc->font); return fontdesc; }
/* Render a glyph and return a bitmap. If the glyph is too large to fit the cache we have two choices: 1) Return NULL so the caller can draw the glyph using an outline. Only supported for freetype fonts. 2) Render a clipped glyph by using the scissor rectangle. Only supported for type 3 fonts. This must not be inserted into the cache. */ fz_pixmap * fz_render_glyph(fz_context *ctx, fz_font *font, int gid, const fz_matrix *ctm, fz_colorspace *model, fz_irect scissor) { fz_glyph_cache *cache; fz_glyph_key key; fz_pixmap *val; float size = fz_matrix_expansion(ctm); int do_cache, locked, caching; fz_matrix local_ctm = *ctm; fz_glyph_cache_entry *entry; unsigned hash; fz_var(locked); fz_var(caching); if (size <= MAX_GLYPH_SIZE) { scissor = fz_infinite_irect; do_cache = 1; } else { /* SumatraPDF: don't break clipping by larger glyphs */ if (font->ft_face && size > 3000) return NULL; do_cache = 0; } cache = ctx->glyph_cache; memset(&key, 0, sizeof key); key.font = font; key.gid = gid; key.a = local_ctm.a * 65536; key.b = local_ctm.b * 65536; key.c = local_ctm.c * 65536; key.d = local_ctm.d * 65536; key.e = (local_ctm.e - floorf(local_ctm.e)) * 256; key.f = (local_ctm.f - floorf(local_ctm.f)) * 256; key.aa = fz_aa_level(ctx); local_ctm.e = floorf(local_ctm.e) + key.e / 256.0f; local_ctm.f = floorf(local_ctm.f) + key.f / 256.0f; fz_lock(ctx, FZ_LOCK_GLYPHCACHE); hash = do_hash((unsigned char *)&key, sizeof(key)) % GLYPH_HASH_LEN; entry = cache->entry[hash]; while (entry) { if (memcmp(&entry->key, &key, sizeof(key)) == 0) { move_to_front(cache, entry); val = fz_keep_pixmap(ctx, entry->val); fz_unlock(ctx, FZ_LOCK_GLYPHCACHE); return val; } entry = entry->bucket_next; } locked = 1; caching = 0; fz_try(ctx) { if (font->ft_face) { val = fz_render_ft_glyph(ctx, font, gid, &local_ctm, key.aa); } else if (font->t3procs) { /* We drop the glyphcache here, and execute the t3 * glyph code. The danger here is that some other * thread will come along, and want the same glyph * too. If it does, we may both end up rendering * pixmaps. We cope with this later on, by ensuring * that only one gets inserted into the cache. If * we insert ours to find one already there, we * abandon ours, and use the one there already. */ fz_unlock(ctx, FZ_LOCK_GLYPHCACHE); locked = 0; val = fz_render_t3_glyph(ctx, font, gid, &local_ctm, model, scissor); fz_lock(ctx, FZ_LOCK_GLYPHCACHE); locked = 1; } else { fz_warn(ctx, "assert: uninitialized font structure"); val = NULL; } if (val && do_cache) { if (val->w < MAX_GLYPH_SIZE && val->h < MAX_GLYPH_SIZE) { /* If we throw an exception whilst caching, * just ignore the exception and carry on. */ caching = 1; if (!font->ft_face) { /* We had to unlock. Someone else might * have rendered in the meantime */ entry = cache->entry[hash]; while (entry) { if (memcmp(&entry->key, &key, sizeof(key)) == 0) { fz_drop_pixmap(ctx, val); move_to_front(cache, entry); val = fz_keep_pixmap(ctx, entry->val); fz_unlock(ctx, FZ_LOCK_GLYPHCACHE); return val; } entry = entry->bucket_next; } } entry = fz_malloc_struct(ctx, fz_glyph_cache_entry); entry->key = key; entry->hash = hash; entry->bucket_next = cache->entry[hash]; if (entry->bucket_next) entry->bucket_next->bucket_prev = entry; cache->entry[hash] = entry; entry->val = fz_keep_pixmap(ctx, val); fz_keep_font(ctx, key.font); entry->lru_next = cache->lru_head; if (entry->lru_next) entry->lru_next->lru_prev = entry; else cache->lru_tail = entry; cache->lru_head = entry; cache->total += val->w * val->h; while (cache->total > MAX_CACHE_SIZE) { drop_glyph_cache_entry(ctx, cache->lru_tail); } } } } fz_always(ctx) { if (locked) fz_unlock(ctx, FZ_LOCK_GLYPHCACHE); } fz_catch(ctx) { if (caching) fz_warn(ctx, "cannot encache glyph; continuing"); else fz_rethrow(ctx); } return val; }