diff options
Diffstat (limited to 'pdf/pdf_font3.c')
-rw-r--r-- | pdf/pdf_font3.c | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/pdf/pdf_font3.c b/pdf/pdf_font3.c new file mode 100644 index 00000000..155d8be5 --- /dev/null +++ b/pdf/pdf_font3.c @@ -0,0 +1,334 @@ +/* Copyright (C) 2019-2021 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, + modified or distributed except as expressly authorized under the terms + of the license contained in the file LICENSE in this distribution. + + Refer to licensing information at http://www.artifex.com or contact + Artifex Software, Inc., 1305 Grant Avenue - Suite 200, Novato, + CA 94945, U.S.A., +1(415)492-9861, for further information. +*/ + +/* code for type 3 font handling */ + +#include "pdf_int.h" +#include "pdf_stack.h" +#include "pdf_array.h" +#include "pdf_dict.h" +#include "pdf_gstate.h" +#include "pdf_font.h" +#include "pdf_font3.h" +#include "pdf_font_types.h" +#include "pdf_deref.h" +#include "gscencs.h" +#include "gscedata.h" /* For the encoding arrays */ +#include "gsccode.h" /* For the Encoding indices */ +#include "gsuid.h" /* For no_UniqueID */ +#include "gsutil.h" /* For gs_next_ids() */ + +static void pdfi_type3_copy_color(gs_gstate_color *src, gs_gstate_color *dest) +{ + *dest->ccolor = *src->ccolor; + *dest->dev_color = *src->dev_color; + dest->color_space = src->color_space; + dest->effective_opm = src->effective_opm; +} + +static int +pdfi_type3_build_char(gs_show_enum * penum, gs_gstate * pgs, gs_font * pfont, + gs_char chr, gs_glyph glyph) +{ + int code = 0; + pdf_font_type3 *font; + pdf_name *GlyphName = NULL; + pdf_stream *CharProc = NULL; + int SavedTextBlockDepth = 0; + char Notdef[8] = {".notdef"}; + + font = (pdf_font_type3 *)pfont->client_data; + + SavedTextBlockDepth = OBJ_CTX(font)->text.BlockDepth; + code = pdfi_array_get(OBJ_CTX(font), font->Encoding, (uint64_t)chr, (pdf_obj **)&GlyphName); + if (code < 0) + return code; + + code = pdfi_dict_get_by_key(OBJ_CTX(font), font->CharProcs, GlyphName, (pdf_obj **)&CharProc); + if (code == gs_error_undefined) { + byte *Key = NULL; + /* Can't find the named glyph, try to find a /.notdef as a substitute */ + Key = gs_alloc_bytes(OBJ_MEMORY(font), 8, "working buffer for BuildChar"); + if (Key == NULL) + goto build_char_error; + memset(Key, 0x00, 8); + memcpy(Key, Notdef, 8); + code = pdfi_dict_get(OBJ_CTX(font), font->CharProcs, (const char *)Key, (pdf_obj **)&CharProc); + gs_free_object(OBJ_MEMORY(font), Key, "working buffer for BuildChar"); + if (code == gs_error_undefined) { + code = 0; + goto build_char_error; + } + } + if (code < 0) + goto build_char_error; + if (CharProc->type != PDF_STREAM) { + code = gs_note_error(gs_error_typecheck); + goto build_char_error; + } + + OBJ_CTX(font)->text.BlockDepth = 0; + OBJ_CTX(font)->text.inside_CharProc = true; + OBJ_CTX(font)->text.CharProc_is_d1 = false; + + { + /* It turns out that if a type 3 font uses a stroke to draw, and does not + * acrually set the stroke colour, then we must use the fill colour instead. + * In effect we start a type 3 BuildChar with stroke colour = fill colour. + * That is annoyingly difficult to set up. We need to copy the existing + * colour values from the structures in the gs_gstate_color structures into + * temporary copies and copy the colour space pointer (and keep its reference + * count correct). Then copy the fill colour values and ponter to the stroke + * structures. Finally, after drawing the character, copy the temporary + * saved copies back again. + */ + gs_gstate_color tmp_color; + gs_client_color tmp_cc; + gx_device_color tmp_dc; + + /* Set up the pointers in the gs_gstate_color structure to point to + * the temporary structures we have on the stack. + */ + tmp_color.ccolor = &tmp_cc; + tmp_color.dev_color = &tmp_dc; + + /* Use the utility routine above to copy the stroke colour to the temporary copy */ + pdfi_type3_copy_color(&OBJ_CTX(font)->pgs->color[1], &tmp_color); + rc_increment_cs(tmp_color.color_space); + /* Use the utility routine above to copy the fill colour to the stroke colour */ + pdfi_type3_copy_color(&OBJ_CTX(font)->pgs->color[0], &OBJ_CTX(font)->pgs->color[1]); + + pdfi_gsave(OBJ_CTX(font)); + pdfi_run_context(OBJ_CTX(font), CharProc, font->PDF_font, true, "CharProc"); + pdfi_grestore(OBJ_CTX(font)); + + /* Use the utility routine above to copy the temporary copy to the stroke colour */ + pdfi_type3_copy_color(&tmp_color, &OBJ_CTX(font)->pgs->color[1]); + rc_decrement_cs(tmp_color.color_space, "pdfi_type3_build_char"); + } + + OBJ_CTX(font)->text.inside_CharProc = false; + OBJ_CTX(font)->text.CharProc_is_d1 = false; + OBJ_CTX(font)->text.BlockDepth = SavedTextBlockDepth; + +build_char_error: + pdfi_countdown(GlyphName); + pdfi_countdown(CharProc); + return code; +} + +static int alloc_type3_font(pdf_context *ctx, pdf_font_type3 **font) +{ + pdf_font_type3 *t3font = NULL; + + t3font = (pdf_font_type3 *)gs_alloc_bytes(ctx->memory, sizeof(pdf_font_type3), "pdfi_alloc_type3_font"); + if (t3font == NULL) + return_error(gs_error_VMerror); + + memset(t3font, 0x00, sizeof(pdf_font_type3)); + (t3font)->ctx = ctx; + (t3font)->type = PDF_FONT; + +#if REFCNT_DEBUG + (t3font)->UID = ctx->UID++; + dmprintf2(ctx->memory, "Allocated object of type %c with UID %"PRIi64"\n", t3font->type, t3font->UID); +#endif + + + pdfi_countup(t3font); + + t3font->pfont = gs_alloc_struct(ctx->memory, gs_font_base, &st_gs_font_base, + "pdfi (type 3 font)"); + if (t3font->pfont == NULL) { + pdfi_countdown(t3font); + return_error(gs_error_VMerror); + } + + memset(t3font->pfont, 0x00, sizeof(gs_font_base)); + t3font->ctx = ctx; + t3font->pdfi_font_type = e_pdf_font_type3; + + gs_make_identity(&t3font->pfont->orig_FontMatrix); + gs_make_identity(&t3font->pfont->FontMatrix); + t3font->pfont->next = t3font->pfont->prev = 0; + t3font->pfont->memory = ctx->memory; + t3font->pfont->dir = ctx->font_dir; + t3font->pfont->is_resource = false; + gs_notify_init(&t3font->pfont->notify_list, ctx->memory); + t3font->pfont->base = (gs_font *) t3font->pfont; + t3font->pfont->client_data = t3font; + t3font->pfont->WMode = 0; + t3font->pfont->PaintType = 0; + t3font->pfont->StrokeWidth = 0; + t3font->pfont->is_cached = 0; + t3font->pfont->procs.init_fstack = gs_default_init_fstack; + t3font->pfont->procs.next_char_glyph = gs_default_next_char_glyph; + t3font->pfont->FAPI = NULL; + t3font->pfont->FAPI_font_data = NULL; + t3font->pfont->procs.glyph_name = ctx->get_glyph_name; + t3font->pfont->procs.decode_glyph = pdfi_decode_glyph; + t3font->pfont->procs.define_font = gs_no_define_font; + t3font->pfont->procs.make_font = gs_no_make_font; + t3font->pfont->procs.font_info = gs_default_font_info; + t3font->pfont->procs.glyph_info = gs_default_glyph_info; + t3font->pfont->procs.glyph_outline = gs_no_glyph_outline; + t3font->pfont->procs.encode_char = pdfi_encode_char; + t3font->pfont->procs.build_char = pdfi_type3_build_char; + t3font->pfont->procs.same_font = gs_default_same_font; + t3font->pfont->procs.enumerate_glyph = gs_no_enumerate_glyph; + + t3font->pfont->FontType = ft_PDF_user_defined; + /* outlines ? Bitmaps ? */ + t3font->pfont->ExactSize = fbit_use_bitmaps; + t3font->pfont->InBetweenSize = fbit_use_bitmaps; + t3font->pfont->TransformedChar = fbit_transform_bitmaps; + + t3font->pfont->encoding_index = 1; /****** WRONG ******/ + t3font->pfont->nearest_encoding_index = 1; /****** WRONG ******/ + + t3font->pfont->client_data = (void *)t3font; + t3font->pfont->id = gs_next_ids(ctx->memory, 1); + uid_set_UniqueID(&t3font->pfont->UID, no_UniqueID); + + *font = (pdf_font_type3 *)t3font; + return 0; +} + +int pdfi_free_font_type3(pdf_obj *font) +{ + pdf_font_type3 *t3font = (pdf_font_type3 *)font; + + if (t3font->pfont) + gs_free_object(OBJ_MEMORY(t3font), t3font->pfont, "Free type 3 font"); + + if (t3font->Widths) + gs_free_object(OBJ_MEMORY(t3font), t3font->Widths, "Free type 3 font Widths array"); + + pdfi_countdown(t3font->PDF_font); + pdfi_countdown(t3font->FontDescriptor); + pdfi_countdown(t3font->CharProcs); + pdfi_countdown(t3font->Encoding); + gs_free_object(OBJ_MEMORY(font), font, "Free type 3 font"); + return 0; +} + + +int pdfi_read_type3_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict, pdf_dict *page_dict, pdf_font **ppdffont) +{ + int code = 0, i, num_chars = 0; + pdf_font_type3 *font = NULL; + pdf_obj *obj = NULL; + double f; + + *ppdffont = NULL; + code = alloc_type3_font(ctx, &font); + if (code < 0) + return code; + + font->object_num = font_dict->object_num; + + code = pdfi_dict_get_type(ctx, font_dict, "FontBBox", PDF_ARRAY, &obj); + if (code < 0) + goto font3_error; + code = pdfi_array_to_gs_rect(ctx, (pdf_array *)obj, &font->pfont->FontBBox); + if (code < 0) + goto font3_error; + pdfi_countdown(obj); + obj = NULL; + + code = pdfi_dict_get_type(ctx, font_dict, "FontMatrix", PDF_ARRAY, &obj); + if (code < 0) + goto font3_error; + code = pdfi_array_to_gs_matrix(ctx, (pdf_array *)obj, &font->pfont->orig_FontMatrix); + if (code < 0) + goto font3_error; + code = pdfi_array_to_gs_matrix(ctx, (pdf_array *)obj, &font->pfont->FontMatrix); + if (code < 0) + goto font3_error; + pdfi_countdown(obj); + obj = NULL; + + code = pdfi_dict_get(ctx, font_dict, "CharProcs", (pdf_obj **)&font->CharProcs); + if (code < 0) + goto font3_error; + + code = pdfi_dict_get_number(ctx, font_dict, "FirstChar", &f); + if (code < 0) + goto font3_error; + font->FirstChar = (int)f; + + code = pdfi_dict_get_number(ctx, font_dict, "LastChar", &f); + if (code < 0) + goto font3_error; + font->LastChar = (int)f; + + num_chars = (font->LastChar - font->FirstChar) + 1; + code = pdfi_dict_knownget_type(ctx, font_dict, "FontDescriptor", PDF_DICT, (pdf_obj **)&font->FontDescriptor); + if (code < 0) + goto font3_error; + + code = pdfi_dict_knownget_type(ctx, font_dict, "Widths", PDF_ARRAY, (pdf_obj **)&obj); + if (code < 0) + goto font3_error; + if (code > 0) { + if (num_chars != pdfi_array_size((pdf_array *)obj)) { + code = gs_note_error(gs_error_rangecheck); + goto font3_error; + } + + font->Widths = (double *)gs_alloc_bytes(ctx->memory, sizeof(double) * num_chars, "type 3 font Widths array"); + if (font->Widths == NULL) { + code = gs_note_error(gs_error_VMerror); + goto font3_error; + } + memset(font->Widths, 0x00, sizeof(double) * num_chars); + for (i = 0; i < num_chars; i++) { + code = pdfi_array_get_number(ctx, (pdf_array *)obj, (uint64_t)i, &font->Widths[i]); + if (code < 0) + goto font3_error; + } + } + pdfi_countdown(obj); + obj = NULL; + + code = pdfi_dict_get(ctx, font_dict, "Encoding", &obj); + if (code < 0) + goto font3_error; + + code = pdfi_create_Encoding(ctx, obj, NULL, (pdf_obj **)&font->Encoding); + if (code < 0) + goto font3_error; + pdfi_countdown(obj); + + font->PDF_font = font_dict; + pdfi_countup(font_dict); + + code = replace_cache_entry(ctx, (pdf_obj *)font); + if (code < 0) + goto font3_error; + + code = gs_definefont(ctx->font_dir, (gs_font *)font->pfont); + if (code < 0) + goto font3_error; + + *ppdffont = (pdf_font *)font; + + return code; + +font3_error: + pdfi_countdown(obj); + pdfi_countdown(font); + return code; +} |