Files
ElyOffice/crates/ely-pdf-engine/shim/ely_pen.c
T
ZacharyZhang-NYandClaude Opus 5.5 68b5af76e0 Windows and Linux build environments; check clean on both (E-01)
MuPDF builds with MSBuild on Windows (/MT, OpenSSL from vcpkg);
Git for Windows' MinGit stands in for the source build there. CEF
loads from where libcef lives and sets its API version first on
every platform. File identity on Windows compares volume and index.
The checkout and reference/ keep LF on Windows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 03:53:56 -04:00

197 lines
5.7 KiB
C

/* The font new text is written in (PDF-03). */
#include <string.h>
#include "ely_shim.h"
/* The script face for typed signatures, from the worker. */
static const unsigned char *script_data;
static size_t script_len;
void ely_script_font(const unsigned char *data, size_t len)
{
script_data = data;
script_len = len;
}
/* `cid` as text extraction reads it (pdf-op-run.c), or -1. */
static int unicode_of(pdf_font_desc *desc, int cid)
{
int ucs[PDF_MRANGE_CAP], n = 0;
if (desc->to_unicode)
n = pdf_lookup_cmap_full(desc->to_unicode, cid, ucs);
if (n == 1 && ucs[0] >= 8 && ucs[0] <= 13)
ucs[0] = ' ';
if (n == 1 && (ucs[0] < 32 || (ucs[0] >= 127 && ucs[0] < 160)))
n = 0;
if (n == 0 && cid < (int)desc->cid_to_ucs_len)
ucs[0] = desc->cid_to_ucs[cid], n = 1;
return n == 1 && ucs[0] > 0 && ucs[0] != FZ_REPLACEMENT_CHARACTER ? ucs[0] : -1;
}
/* `desc` Unicode-to-code pairs; -1 when codes are not CIDs. */
static int own_codes(fz_context *ctx, pdf_font_desc *desc, ely_pen *p)
{
pdf_cmap *enc = desc->encoding;
int cid, end;
if (!enc || strcmp(enc->cmap_name, "Identity-H") || enc->codespace_len != 1 || enc->codespace[0].n > 2)
return -1;
p->bytes = enc->codespace[0].n;
end = 1 << (8 * p->bytes);
p->map = fz_malloc_array(ctx, 2 * end, int);
for (cid = 0; cid < end; cid++)
{
int u = unicode_of(desc, cid);
if (u > 0 && pdf_font_cid_to_gid(ctx, desc, cid) > 0)
p->map[2 * p->mapped] = u, p->map[2 * p->mapped + 1] = cid, p->mapped++;
}
return 0;
}
/* The page font drawn as `own`; -1: cannot write. */
static int own_font(fz_context *ctx, pdf_page *page, fz_font *own, ely_pen *p)
{
pdf_obj *res = pdf_page_resources(ctx, page);
pdf_resource_stack stack = { NULL, res };
pdf_obj *fonts = pdf_dict_get(ctx, res, PDF_NAME(Font));
int i, n = pdf_dict_len(ctx, fonts);
for (i = 0; i < n && !p->desc; i++)
{
pdf_font_desc *desc = pdf_load_font(ctx, page->doc, &stack, pdf_dict_get_val(ctx, fonts, i));
if (desc->font != own)
{
pdf_drop_font(ctx, desc);
continue;
}
p->desc = desc;
/* A direct font cannot be named again after the edit. */
p->num = pdf_to_num(ctx, pdf_dict_get_val(ctx, fonts, i));
return p->num ? own_codes(ctx, desc, p) : -1;
}
/* Drawn from elsewhere, as in a form: not writable here. */
return -1;
}
int ely_choose_pen(fz_context *ctx, const char *choice, fz_font *own, pdf_page *page, ely_pen *p)
{
static const struct { const char *choice, *name; } latin[] = {
{ "helvetica", "Helvetica" }, { "times", "Times-Roman" }, { "courier", "Courier" } };
static const struct { const char *choice; int ordering; } cjk[] = {
{ "cjk-sc", FZ_ADOBE_GB }, { "cjk-tc", FZ_ADOBE_CNS }, { "cjk-jp", FZ_ADOBE_JAPAN }, { "cjk-kr", FZ_ADOBE_KOREA } };
size_t i;
if (!strcmp(choice, "script"))
{
if (!script_data)
fz_throw(ctx, FZ_ERROR_ARGUMENT, "no script font was given");
p->kind = PEN_CID;
p->font = fz_new_font_from_memory(ctx, "GreatVibes", script_data, (int)script_len, 0, 0);
return 0;
}
if (!strcmp(choice, "original"))
{
if (!own)
fz_throw(ctx, FZ_ERROR_ARGUMENT, "the block has no font of its own");
p->kind = PEN_OWN;
return own_font(ctx, page, own, p);
}
for (i = 0; i < nelem(latin); i++)
if (!strcmp(choice, latin[i].choice))
{
p->kind = PEN_SIMPLE;
p->font = fz_new_base14_font(ctx, latin[i].name);
return 0;
}
for (i = 0; i < nelem(cjk); i++)
if (!strcmp(choice, cjk[i].choice))
{
p->kind = PEN_CJK;
p->ordering = cjk[i].ordering;
p->font = fz_new_cjk_font(ctx, cjk[i].ordering);
return 0;
}
fz_throw(ctx, FZ_ERROR_ARGUMENT, "no font %s", choice);
}
const char *ely_pen_resource(fz_context *ctx, pdf_document *pdf, pdf_page *page, ely_pen *p, char *name, size_t room)
{
pdf_drop_obj(ctx, p->ref);
p->ref = NULL;
switch (p->kind)
{
case PEN_OWN:
/* Removing the block may drop the font from the page. */
p->ref = pdf_new_indirect(ctx, pdf, p->num, 0);
break;
case PEN_CID:
p->ref = pdf_add_cid_font(ctx, pdf, p->font);
break;
case PEN_SIMPLE:
p->ref = pdf_add_simple_font(ctx, pdf, p->font, PDF_SIMPLE_ENCODING_LATIN);
break;
case PEN_CJK:
p->ref = pdf_add_cjk_font(ctx, pdf, p->font, p->ordering, 0, 0);
break;
}
return ely_add_resource(ctx, page->obj, PDF_NAME(Font), "ElyF", p->ref, name, room);
}
/* The own font's code for `u`, or -1. */
static int own_code(ely_pen *p, int u)
{
int i;
for (i = 0; i < p->mapped; i++)
if (p->map[2 * i] == u)
return p->map[2 * i + 1];
return -1;
}
/* The new font's glyph for `u`, or 0. */
static int glyph(fz_context *ctx, ely_pen *p, int u)
{
if (p->kind == PEN_SIMPLE && fz_windows_1252_from_unicode(u) < 0)
return 0;
return fz_encode_character(ctx, p->font, u);
}
int ely_pen_has(fz_context *ctx, ely_pen *p, int u)
{
return p->kind == PEN_OWN ? own_code(p, u) >= 0 : glyph(ctx, p, u) > 0;
}
float ely_pen_advance(fz_context *ctx, ely_pen *p, int u, float size)
{
if (p->kind == PEN_OWN)
return pdf_lookup_hmtx(ctx, p->desc, own_code(p, u)).w * size / 1000;
return fz_advance_glyph(ctx, p->font, glyph(ctx, p, u), 0) * size;
}
void ely_pen_code(fz_context *ctx, fz_buffer *buf, ely_pen *p, int u)
{
switch (p->kind)
{
case PEN_OWN:
fz_append_printf(ctx, buf, p->bytes == 1 ? "%02x" : "%04x", own_code(p, u));
break;
case PEN_CID:
fz_append_printf(ctx, buf, "%04x", glyph(ctx, p, u));
break;
case PEN_SIMPLE:
fz_append_printf(ctx, buf, "%02x", fz_windows_1252_from_unicode(u));
break;
case PEN_CJK:
if (u > 0xffff)
fz_append_printf(ctx, buf, "%04x%04x", 0xd800 + ((u - 0x10000) >> 10), 0xdc00 + ((u - 0x10000) & 0x3ff));
else
fz_append_printf(ctx, buf, "%04x", u);
break;
}
}
void ely_drop_pen(fz_context *ctx, ely_pen *p)
{
fz_drop_font(ctx, p->font);
pdf_drop_obj(ctx, p->ref);
pdf_drop_font(ctx, p->desc);
fz_free(ctx, p->map);
}