diff options
Diffstat (limited to 'pdf/pdf_font11.c')
-rw-r--r-- | pdf/pdf_font11.c | 462 |
1 files changed, 462 insertions, 0 deletions
diff --git a/pdf/pdf_font11.c b/pdf/pdf_font11.c new file mode 100644 index 00000000..ebe0cd21 --- /dev/null +++ b/pdf/pdf_font11.c @@ -0,0 +1,462 @@ +/* Copyright (C) 2020-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 CIDFontType2/Type 9 font handling */ +/* CIDFonts with Truetype outlines */ + +#include "pdf_int.h" +#include "pdf_font.h" +#include "pdf_font0.h" +#include "pdf_fontTT.h" +#include "pdf_font_types.h" +#include "pdf_stack.h" +#include "pdf_file.h" +#include "pdf_dict.h" +#include "pdf_array.h" +#include "pdf_deref.h" +#include "gxfont42.h" +#include "gxfcid.h" +#include "gsutil.h" /* For gs_next_ids() */ + +static int pdfi_cidtype2_string_proc(gs_font_type42 * pfont, ulong offset, uint length, + const byte ** pdata) +{ + pdf_cidfont_type2 *ttfont = (pdf_cidfont_type2 *)pfont->client_data; + int code = 0; + + if (offset + length > ttfont->sfnt.size) { + *pdata = NULL; + code = gs_note_error(gs_error_invalidfont); + } + else { + *pdata = ttfont->sfnt.data + offset; + } + return code; +} + +static int pdfi_cidtype2_CIDMap_proc(gs_font_cid2 *pfont, gs_glyph glyph) +{ + pdf_cidfont_type2 *pdffont11 = (pdf_cidfont_type2 *)pfont->client_data; + uint gid = glyph - GS_MIN_CID_GLYPH; + + if (pdffont11->cidtogidmap.size > (gid << 1) + 1) { + gid = pdffont11->cidtogidmap.data[gid << 1] << 8 | pdffont11->cidtogidmap.data[(gid << 1) + 1]; + } + + return (int)gid; +} + +static uint pdfi_cidtype2_get_glyph_index(gs_font_type42 *pfont, gs_glyph glyph) +{ + pdf_cidfont_type2 *pdffont11 = (pdf_cidfont_type2 *)pfont->client_data; + uint gid; + + if (glyph < GS_MIN_CID_GLYPH) { + gid = 0; + } + else { + if (glyph < GS_MIN_GLYPH_INDEX) { + gid = glyph - GS_MIN_CID_GLYPH; + if (pdffont11->cidtogidmap.size > 0) { + gid = pdffont11->cidtogidmap.data[gid << 1] << 8 | pdffont11->cidtogidmap.data[(gid << 1) + 1]; + } + } + else { + gid = (uint)(glyph - GS_MIN_GLYPH_INDEX); + } + } + + return gid; +} + +static int +pdfi_cidtype2_glyph_info(gs_font *font, gs_glyph glyph, const gs_matrix *pmat, + int members, gs_glyph_info_t *info) +{ + int code; + pdf_cidfont_type2 *pdffont11 = (pdf_cidfont_type2 *)font->client_data; + code = (*pdffont11->orig_glyph_info)(font, glyph, pmat, members, info); + if (code < 0) + return code; + + if ((members & GLYPH_INFO_WIDTHS) != 0 + && glyph > GS_MIN_CID_GLYPH + && glyph < GS_MIN_GLYPH_INDEX) { + double widths[6] = {0}; + code = pdfi_get_cidfont_glyph_metrics(font, (glyph - GS_MIN_CID_GLYPH), widths, true); + if (code >= 0) { + if (pmat == NULL) { + info->width[0].x = widths[GLYPH_W0_WIDTH_INDEX] / 1000.0; + info->width[0].y = widths[GLYPH_W0_HEIGHT_INDEX] / 1000.0; + } + else { + code = gs_point_transform(widths[GLYPH_W0_WIDTH_INDEX] / 1000.0, widths[GLYPH_W0_HEIGHT_INDEX] / 1000.0, pmat, &info->width[0]); + if (code < 0) + return code; + } + info->members |= GLYPH_INFO_WIDTH0; + + if ((members & GLYPH_INFO_WIDTH1) != 0 + && (widths[GLYPH_W1_WIDTH_INDEX] != 0 + || widths[GLYPH_W1_HEIGHT_INDEX] != 0)) { + if (pmat == NULL) { + info->width[1].x = widths[GLYPH_W1_WIDTH_INDEX] / 1000.0; + info->width[1].y = widths[GLYPH_W1_HEIGHT_INDEX] / 1000.0; + } + else { + code = gs_point_transform(widths[GLYPH_W1_WIDTH_INDEX] / 1000.0, widths[GLYPH_W1_HEIGHT_INDEX] / 1000.0, pmat, &info->width[1]); + if (code < 0) + return code; + } + info->members |= GLYPH_INFO_WIDTH1; + } + if ((members & GLYPH_INFO_VVECTOR1) != 0) { + if (pmat == NULL) { + info->v.x = widths[GLYPH_W1_V_X_INDEX] / 1000.0; + info->v.y = widths[GLYPH_W1_V_Y_INDEX] / 1000.0; + } + else { + code = gs_point_transform(widths[GLYPH_W1_V_X_INDEX] / 1000.0, widths[GLYPH_W1_V_Y_INDEX] / 1000.0, pmat, &info->v); + if (code < 0) + return code; + } + info->members |= GLYPH_INFO_VVECTOR1; + } + } + } + return code; +} + +static int +pdfi_cidtype2_enumerate_glyph(gs_font *font, int *pindex, + gs_glyph_space_t glyph_space, gs_glyph *pglyph) +{ + int code = 0; + gs_font_cid2 *cid2 = (gs_font_cid2 *)font; + pdf_cidfont_type2 *pdffont11 = (pdf_cidfont_type2 *)font->client_data; + *pglyph = 0; + + if (*pindex <= 0) + *pindex = 0; + + if (pdffont11->cidtogidmap.size > 0) { + do { + *pglyph = pdffont11->cidtogidmap.data[(*pindex) << 1] << 8 | pdffont11->cidtogidmap.data[((*pindex) << 1) + 1]; + (*pindex)++; + if (*pglyph == 0 && *pindex == 1) /* notdef - special case */ + break; + } while (*pglyph == 0 && ((*pindex) << 1) < pdffont11->cidtogidmap.size); + + if (((*pindex) << 1) >= pdffont11->cidtogidmap.size) { + *pindex = 0; + } + else { + if (*pglyph != 0 || (*pglyph == 0 && *pindex == 1)) { + if (glyph_space == GLYPH_SPACE_INDEX) { + *pglyph += GS_MIN_GLYPH_INDEX; + } + else { + *pglyph = (*pindex) + GS_MIN_CID_GLYPH; + } + } + } + } + else { + if (*pindex < cid2->cidata.common.CIDCount) { + if (glyph_space == GLYPH_SPACE_INDEX) { + *pglyph = *pindex + GS_MIN_GLYPH_INDEX; + } + else { + *pglyph = (*pindex) + GS_MIN_CID_GLYPH; + } + } + else { + *pindex = 0; + } + } + + return code; +} + +static int +pdfi_alloc_cidtype2_font(pdf_context *ctx, pdf_cidfont_type2 **font, bool is_cid) +{ + pdf_cidfont_type2 *ttfont = NULL; + gs_font_cid2 *pfont = NULL; + + ttfont = (pdf_cidfont_type2 *)gs_alloc_bytes(ctx->memory, sizeof(pdf_cidfont_type2), "pdfi (cidtype2 pdf_font)"); + if (ttfont == NULL) + return_error(gs_error_VMerror); + + memset(ttfont, 0x00, sizeof(pdf_cidfont_type2)); + ttfont->type = PDF_FONT; + ttfont->ctx = ctx; + ttfont->pdfi_font_type = e_pdf_cidfont_type2; + +#if REFCNT_DEBUG + ttfont->UID = ctx->UID++; + dmprintf2(ctx->memory, "Allocated object of type %c with UID %"PRIi64"\n", ttfont->type, ttfont->UID); +#endif + + pdfi_countup(ttfont); + + pfont = (gs_font_cid2 *)gs_alloc_struct(ctx->memory, gs_font_cid2, &st_gs_font_cid2, + "pdfi (cidtype2 pfont)"); + if (pfont == NULL) { + pdfi_countdown(ttfont); + return_error(gs_error_VMerror); + } + memset(pfont, 0x00, sizeof(gs_font_cid2)); + + ttfont->pfont = (gs_font_base *)pfont; + + gs_make_identity(&pfont->orig_FontMatrix); + gs_make_identity(&pfont->FontMatrix); + pfont->next = pfont->prev = 0; + pfont->memory = ctx->memory; + pfont->dir = ctx->font_dir; + pfont->is_resource = false; + gs_notify_init(&pfont->notify_list, ctx->memory); + pfont->base = (gs_font *) ttfont->pfont; + pfont->client_data = ttfont; + pfont->WMode = 0; + pfont->PaintType = 0; + pfont->StrokeWidth = 0; + pfont->is_cached = 0; + pfont->FAPI = NULL; + pfont->FAPI_font_data = NULL; + pfont->procs.init_fstack = gs_default_init_fstack; + pfont->procs.next_char_glyph = gs_default_next_char_glyph; + pfont->FontType = ft_CID_TrueType; + pfont->ExactSize = fbit_use_outlines; + pfont->InBetweenSize = fbit_use_outlines; + pfont->TransformedChar = fbit_use_outlines; + /* We may want to do something clever with an XUID here */ + pfont->id = gs_next_ids(ctx->memory, 1); + uid_set_UniqueID(&pfont->UID, pfont->id); + /* The buildchar proc will be filled in by FAPI - + we won't worry about working without FAPI */ + pfont->procs.encode_char = pdfi_encode_char; + pfont->data.string_proc = pdfi_cidtype2_string_proc; + pfont->procs.glyph_name = ctx->get_glyph_name; + pfont->procs.decode_glyph = pdfi_decode_glyph; + pfont->procs.define_font = gs_no_define_font; + pfont->procs.make_font = gs_no_make_font; + pfont->procs.font_info = gs_default_font_info; + pfont->procs.glyph_info = gs_default_glyph_info; + pfont->procs.glyph_outline = gs_no_glyph_outline; + pfont->procs.build_char = NULL; + pfont->procs.same_font = gs_default_same_font; + pfont->procs.enumerate_glyph = gs_no_enumerate_glyph; + + pfont->encoding_index = 1; /****** WRONG ******/ + pfont->nearest_encoding_index = 1; /****** WRONG ******/ + + cid_system_info_set_null(&pfont->cidata.common.CIDSystemInfo); + pfont->cidata.common.CIDCount = 0; /* set later */ + pfont->cidata.common.GDBytes = 2; /* not used */ + pfont->cidata.MetricsCount = 0; + pfont->cidata.CIDMap_proc = pdfi_cidtype2_CIDMap_proc; + + pfont->client_data = (void *)ttfont; + + *font = ttfont; + return 0; +} + +int pdfi_read_cidtype2_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict, pdf_dict *page_dict, byte *buf, int64_t buflen, pdf_font **ppfont) +{ + pdf_cidfont_type2 *font; + int code = 0; + pdf_obj *fontdesc = NULL; + pdf_obj *obj = NULL; + gs_font_cid2 *cid2; + + if (ppfont == NULL) + return_error(gs_error_invalidaccess); + + *ppfont = NULL; + + code = pdfi_dict_knownget_type(ctx, font_dict, "FontDescriptor", PDF_DICT, &fontdesc); + if (code <= 0) { + /* We own the buffer now, so we must free it on error */ + gs_free_object(ctx->memory, buf, "pdfi_read_cidtype2_font"); + return_error(gs_error_invalidfont); + } + + if ((code = pdfi_alloc_cidtype2_font(ctx, &font, false)) < 0) { + /* We own the buffer now, so we must free it on error */ + gs_free_object(ctx->memory, buf, "pdfi_read_cidtype2_font"); + pdfi_countdown(fontdesc); + return code; + } + font->PDF_font = font_dict; + pdfi_countup(font_dict); + font->object_num = font_dict->object_num; + font->generation_num = font_dict->generation_num; + font->FontDescriptor = (pdf_dict *)fontdesc; + fontdesc = NULL; + + /* Ownership of buf is now part of the font and managed via its lifetime */ + font->sfnt.data = buf; + font->sfnt.size = buflen; + + /* Strictly speaking BaseFont is required, but we can continue without one */ + code = pdfi_dict_knownget_type(ctx, font_dict, "BaseFont", PDF_NAME, (pdf_obj **)&obj); + if (code > 0) { + pdf_name *nobj = (pdf_name *)obj; + int nlen = nobj->length > gs_font_name_max ? gs_font_name_max : nobj->length; + + memcpy(font->pfont->key_name.chars, nobj->data, nlen); + font->pfont->key_name.chars[nlen] = 0; + font->pfont->key_name.size = nlen; + memcpy(font->pfont->font_name.chars, nobj->data, nlen); + font->pfont->font_name.chars[nlen] = 0; + font->pfont->font_name.size = nlen; + pdfi_countdown(obj); + obj = NULL; + } + + code = pdfi_dict_knownget_type(ctx, font_dict, "DW", PDF_INT, (pdf_obj **)&obj); + if (code > 0) { + font->DW = ((pdf_num *)obj)->value.i; + pdfi_countdown(obj); + obj = NULL; + } + else { + font->DW = 1000; + } + code = pdfi_dict_knownget_type(ctx, font_dict, "DW2", PDF_ARRAY, (pdf_obj **)&obj); + if (code > 0) { + font->DW2 = (pdf_array *)obj; + obj = NULL; + } + else { + font->DW2 = NULL; + } + code = pdfi_dict_knownget_type(ctx, font_dict, "W", PDF_ARRAY, (pdf_obj **)&obj); + if (code > 0) { + font->W = (pdf_array *)obj; + obj = NULL; + } + else { + font->W = NULL; + } + code = pdfi_dict_knownget_type(ctx, font_dict, "W2", PDF_ARRAY, (pdf_obj **)&obj); + if (code > 0) { + font->W2 = (pdf_array *)obj; + obj = NULL; + } + else { + font->W2 = NULL; + } + + code = pdfi_dict_knownget(ctx, font_dict, "CIDToGIDMap", (pdf_obj **)&obj); + if (code > 0) { + font->cidtogidmap.data = NULL; + font->cidtogidmap.size = 0; + /* CIDToGIDMap can only be a stream or a name, and if it's a name + it's only permitted to be "/Identity", so ignore it + */ + if (obj->type == PDF_STREAM) { + int64_t sz; + code = pdfi_stream_to_buffer(ctx, (pdf_stream *)obj, &(font->cidtogidmap.data), &sz); + if (code < 0) { + goto error; + } + font->cidtogidmap.size = (uint)sz; + } + pdfi_countdown(obj); + obj = NULL; + } + + code = gs_type42_font_init((gs_font_type42 *)font->pfont, 0); + if (code < 0) { + goto error; + } + font->orig_glyph_info = font->pfont->procs.glyph_info; + font->pfont->procs.glyph_info = pdfi_cidtype2_glyph_info; + font->pfont->procs.enumerate_glyph = pdfi_cidtype2_enumerate_glyph; + + cid2 = (gs_font_cid2 *)font->pfont; + if (font->cidtogidmap.size > 0) { + gs_font_cid2 *cid2 = (gs_font_cid2 *)font->pfont; + if (cid2->data.numGlyphs > font->cidtogidmap.size >> 1) + cid2->cidata.common.CIDCount = cid2->data.numGlyphs; + else { + cid2->cidata.common.CIDCount = font->cidtogidmap.size >> 1; + } + cid2->cidata.common.MaxCID = cid2->cidata.common.CIDCount; + } + else { + gs_font_cid2 *cid2 = (gs_font_cid2 *)font->pfont; + cid2->cidata.common.CIDCount = cid2->data.numGlyphs; + cid2->cidata.common.MaxCID = cid2->cidata.common.CIDCount; + } + cid2->data.substitute_glyph_index_vertical = gs_type42_substitute_glyph_index_vertical; + cid2->cidata.orig_procs.get_outline = cid2->data.get_outline; + cid2->data.get_glyph_index = pdfi_cidtype2_get_glyph_index; + + code = pdfi_font_generate_pseudo_XUID(ctx, font->PDF_font, font->pfont); + if (code < 0) + goto error; + + code = gs_definefont(ctx->font_dir, (gs_font *)font->pfont); + if (code < 0) { + goto error; + } + + code = pdfi_fapi_passfont((pdf_font *)font, 0, NULL, NULL, font->sfnt.data, font->sfnt.size); + if (code < 0) { + goto error; + } + + /* object_num can be zero if the dictionary was defined inline */ + if (font->object_num != 0) { + code = replace_cache_entry(ctx, (pdf_obj *)font); + if (code < 0) + goto error; + } + + *ppfont = (pdf_font *)font; + return code; +error: + + pdfi_countdown(obj); + pdfi_countdown(font); + return code; +} + +int pdfi_free_font_cidtype2(pdf_obj *font) +{ + pdf_cidfont_type2 *pdfcidf = (pdf_cidfont_type2 *)font; + gs_font_cid2 *pfont = (gs_font_cid2 *)pdfcidf->pfont; + gs_free_object(OBJ_MEMORY(pdfcidf), pfont, "pdfi_free_font_cidtype2(pfont)"); + + gs_free_object(OBJ_MEMORY(pdfcidf), pdfcidf->cidtogidmap.data, "pdfi_free_font_cidtype2(cidtogidmap.data)"); + gs_free_object(OBJ_MEMORY(pdfcidf), pdfcidf->sfnt.data, "pdfi_free_font_cidtype2(sfnt.data)"); + + pdfi_countdown(pdfcidf->PDF_font); + pdfi_countdown(pdfcidf->BaseFont); + pdfi_countdown(pdfcidf->FontDescriptor); + pdfi_countdown(pdfcidf->W); + pdfi_countdown(pdfcidf->DW2); + pdfi_countdown(pdfcidf->W2); + + gs_free_object(OBJ_MEMORY(pdfcidf), pdfcidf, "pdfi_free_font_cidtype2(pdfcidf)"); +return 0; + + return 0; +} |