summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'pdf/pdf_font3.c')
-rw-r--r--pdf/pdf_font3.c334
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;
+}