summaryrefslogtreecommitdiff
path: root/src/pdflib/font/ft_truetype.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pdflib/font/ft_truetype.c')
-rw-r--r--src/pdflib/font/ft_truetype.c2310
1 files changed, 2310 insertions, 0 deletions
diff --git a/src/pdflib/font/ft_truetype.c b/src/pdflib/font/ft_truetype.c
new file mode 100644
index 0000000..b4e33a6
--- /dev/null
+++ b/src/pdflib/font/ft_truetype.c
@@ -0,0 +1,2310 @@
+/*---------------------------------------------------------------------------*
+ | PDFlib - A library for generating PDF on the fly |
+ +---------------------------------------------------------------------------+
+ | Copyright (c) 1997-2006 Thomas Merz and PDFlib GmbH. All rights reserved. |
+ +---------------------------------------------------------------------------+
+ | |
+ | This software is subject to the PDFlib license. It is NOT in the |
+ | public domain. Extended versions and commercial licenses are |
+ | available, please check http://www.pdflib.com. |
+ | |
+ *---------------------------------------------------------------------------*/
+
+/* $Id: ft_truetype.c,v 1.1 2008/10/17 06:10:43 scuri Exp $
+ *
+ * FONT TrueType handling routines
+ *
+ */
+
+#include "ft_font.h"
+#include "ft_truetype.h"
+
+#ifdef PDF_TRUETYPE_SUPPORTED
+
+void
+tt_assert(tt_file *ttf)
+{
+ pdc_core *pdc = ttf->pdc;
+
+ if (ttf->filename)
+ pdc_error(pdc, FNT_E_TT_ASSERT2, ttf->filename, 0, 0, 0);
+ else
+ pdc_error(pdc, FNT_E_TT_ASSERT1, 0, 0, 0, 0);
+} /* tt_assert */
+
+void
+tt_error(tt_file *ttf)
+{
+ pdc_core *pdc = ttf->pdc;
+
+ if (ttf->filename)
+ pdc_error(pdc, FNT_E_TT_CORRUPT2, ttf->filename, 0, 0, 0);
+ else
+ pdc_error(pdc, FNT_E_TT_CORRUPT1, 0, 0, 0, 0);
+} /* tt_error */
+
+void
+tt_seek(tt_file *ttf, long offset)
+{
+ if (ttf->incore)
+ {
+ TT_IOCHECK(ttf, ttf->img + (tt_ulong) offset <= ttf->end);
+ ttf->pos = ttf->img + (tt_ulong) offset;
+ }
+ else
+ TT_IOCHECK(ttf, pdc_fseek(ttf->fp, offset, SEEK_SET) == 0);
+}
+
+void
+tt_read(tt_file *ttf, void *buf, unsigned int nbytes)
+{
+ if (ttf->incore)
+ {
+ TT_IOCHECK(ttf, ttf->pos + (tt_ulong) nbytes <= ttf->end);
+ memcpy(buf, ttf->pos, (size_t) nbytes);
+ ttf->pos += (tt_ulong) nbytes;
+ }
+ else
+ TT_IOCHECK(ttf, PDC_OK_FREAD(ttf->fp, buf, nbytes));
+}
+
+long
+tt_tell(tt_file *ttf)
+{
+ if (ttf->incore)
+ return (long) (ttf->pos - ttf->img);
+ else
+ return (long) pdc_ftell(ttf->fp);
+}
+
+tt_ushort
+tt_get_ushort(tt_file *ttf)
+{
+ tt_byte *pos, buf[2];
+
+ if (ttf->incore)
+ {
+ pos = ttf->pos;
+ TT_IOCHECK(ttf, (ttf->pos += 2) <= ttf->end);
+ }
+ else
+ {
+ pos = buf;
+ TT_IOCHECK(ttf, PDC_OK_FREAD(ttf->fp, buf, 2));
+ }
+
+ return pdc_get_be_ushort(pos);
+}
+
+tt_short
+tt_get_short(tt_file *ttf)
+{
+ tt_byte *pos, buf[2];
+
+ if (ttf->incore)
+ {
+ pos = ttf->pos;
+ TT_IOCHECK(ttf, (ttf->pos += 2) <= ttf->end);
+ }
+ else
+ {
+ pos = buf;
+ TT_IOCHECK(ttf, PDC_OK_FREAD(ttf->fp, buf, 2));
+ }
+
+ return pdc_get_be_short(pos);
+}
+
+tt_ulong
+tt_get_ulong3(tt_file *ttf)
+{
+ tt_byte *pos, buf[3];
+
+ if (ttf->incore)
+ {
+ pos = ttf->pos;
+ TT_IOCHECK(ttf, (ttf->pos += 3) <= ttf->end);
+ }
+ else
+ {
+ pos = buf;
+ TT_IOCHECK(ttf, PDC_OK_FREAD(ttf->fp, buf, 3));
+ }
+
+ return pdc_get_be_ulong3(pos);
+}
+
+tt_ulong
+tt_get_ulong(tt_file *ttf)
+{
+ tt_byte *pos, buf[4];
+
+ if (ttf->incore)
+ {
+ pos = ttf->pos;
+ TT_IOCHECK(ttf, (ttf->pos += 4) <= ttf->end);
+ }
+ else
+ {
+ pos = buf;
+ TT_IOCHECK(ttf, PDC_OK_FREAD(ttf->fp, buf, 4));
+ }
+
+ return pdc_get_be_ulong(pos);
+}
+
+tt_long
+tt_get_long(tt_file *ttf)
+{
+ tt_byte *pos, buf[4];
+
+ if (ttf->incore)
+ {
+ pos = ttf->pos;
+ TT_IOCHECK(ttf, (ttf->pos += 4) <= ttf->end);
+ }
+ else
+ {
+ pos = buf;
+ TT_IOCHECK(ttf, PDC_OK_FREAD(ttf->fp, buf, 4));
+ }
+
+ return pdc_get_be_long(pos);
+}
+
+tt_ulong
+tt_get_offset(tt_file *ttf, tt_byte offsize)
+{
+ tt_byte buf;
+
+ switch (offsize)
+ {
+ case 1:
+ tt_read(ttf, &buf, 1);
+ return (tt_ulong) buf;
+
+ case 2:
+ return (tt_ulong) tt_get_ushort(ttf);
+
+ case 3:
+ return (tt_ulong) tt_get_ulong3(ttf);
+
+ case 4:
+ return (tt_ulong) tt_get_ulong(ttf);
+ }
+ return 0;
+}
+
+static void
+tt_get_dirent(tt_dirent *dirent, tt_file *ttf)
+{
+ tt_read(ttf, dirent->tag, 4);
+ dirent->tag[4] = 0;
+ dirent->checksum = tt_get_ulong(ttf);
+ dirent->offset = tt_get_ulong(ttf);
+ dirent->length = tt_get_ulong(ttf);
+} /* tt_get_dirent */
+
+
+int
+tt_tag2idx(tt_file *ttf, char *tag)
+{
+ int i;
+
+ for (i = 0; i < ttf->n_tables; ++i)
+ if (strcmp(ttf->dir[i].tag, tag) == 0)
+ return i;
+
+ return -1;
+} /* tt_tag2idx */
+
+void *
+tt_get_tab(tt_file *ttf, char *tag, size_t nbytes, pdc_bool tterror,
+ tt_ulong *offset)
+{
+ static const char *fn = "tt_get_tab";
+ pdc_core *pdc = ttf->pdc;
+ int idx = tt_tag2idx(ttf, tag);
+
+ if (idx == -1)
+ {
+ if (tterror)
+ tt_error(ttf);
+ return NULL;
+ }
+
+ tt_seek(ttf, (long) ttf->dir[idx].offset);
+
+ if (offset)
+ *offset = ttf->dir[idx].offset;
+
+ return pdc_malloc(pdc, nbytes, fn);
+}
+
+static void
+tt_get_cmap0(tt_file *ttf, tt_cmap0_6 *cm0_6)
+{
+ static const char *fn = "tt_get_cmap0";
+ pdc_core *pdc = ttf->pdc;
+ tt_ushort c;
+ tt_byte buf[256];
+
+ cm0_6->glyphIdArray = (tt_ushort *) 0;
+
+ cm0_6->length = tt_get_ushort(ttf);
+ cm0_6->language = tt_get_ushort(ttf);
+
+ /* These are not used in format 0 */
+ cm0_6->firstCode = 0;
+ cm0_6->entryCount = 256;
+
+ cm0_6->glyphIdArray = (tt_ushort *)
+ pdc_malloc(pdc, (size_t) (sizeof (tt_ushort) * 256), fn);
+
+ tt_read(ttf, buf, 256);
+
+ for (c = 0; c < 256; c++)
+ cm0_6->glyphIdArray[c] = (tt_ushort) buf[c];
+
+} /* tt_get_cmap0 */
+
+static void
+tt_get_cmap6(tt_file *ttf, tt_cmap0_6 *cm0_6)
+{
+ static const char *fn = "tt_get_cmap6";
+ pdc_core *pdc = ttf->pdc;
+ tt_ushort c, last, cmax;
+
+ cm0_6->glyphIdArray = (tt_ushort *) 0;
+
+ cm0_6->length = tt_get_ushort(ttf);
+ cm0_6->language = tt_get_ushort(ttf);
+ cm0_6->firstCode = tt_get_ushort(ttf);
+ cm0_6->entryCount = tt_get_ushort(ttf);
+
+ last = (tt_ushort) (cm0_6->firstCode + cm0_6->entryCount);
+ cmax = MAX(last, 256);
+
+ cm0_6->glyphIdArray = (tt_ushort *)
+ pdc_malloc(pdc, (size_t) (sizeof (tt_ushort) * cmax), fn);
+
+ /* default for codes outside the range specified in this table */
+ for (c = 0; c < cmax; c++)
+ cm0_6->glyphIdArray[c] = (tt_ushort) 0;
+
+ for (c = cm0_6->firstCode; c < last; c++)
+ cm0_6->glyphIdArray[c] = tt_get_ushort(ttf);
+
+} /* tt_get_cmap6 */
+
+static void
+tt_get_cmap4(tt_file *ttf, tt_cmap4 *cm4)
+{
+ static const char *fn = "tt_get_cmap4";
+ pdc_core *pdc = ttf->pdc;
+ int i, segs;
+
+ /* the instruction order is critical for cleanup after exceptions!
+ */
+ cm4->endCount = (tt_ushort *) 0;
+ cm4->startCount = (tt_ushort *) 0;
+ cm4->idDelta = (tt_short *) 0;
+ cm4->idRangeOffs = (tt_ushort *) 0;
+ cm4->glyphIdArray = (tt_ushort *) 0;
+
+ cm4->length = tt_get_ushort(ttf);
+ cm4->version = tt_get_ushort(ttf);
+ cm4->segCountX2 = tt_get_ushort(ttf);
+ cm4->searchRange = tt_get_ushort(ttf);
+ cm4->entrySelector = tt_get_ushort(ttf);
+ cm4->rangeShift = tt_get_ushort(ttf);
+
+ segs = cm4->segCountX2 / 2;
+
+ cm4->numGlyphIds = (tt_ushort)(
+ ((cm4->length - ( 16L + 8L * segs )) & 0xFFFFU) / 2);
+
+ TT_IOCHECK(ttf, 0 <= cm4->numGlyphIds);
+
+ cm4->endCount =
+ (tt_ushort *)
+ pdc_malloc(pdc, (size_t) (sizeof (tt_ushort) * segs), fn);
+ cm4->startCount =
+ (tt_ushort *)
+ pdc_malloc(pdc, (size_t) (sizeof (tt_ushort) * segs), fn);
+ cm4->idDelta =
+ (tt_short *)
+ pdc_malloc(pdc, (size_t) (sizeof (tt_ushort) * segs), fn);
+ cm4->idRangeOffs =
+ (tt_ushort *)
+ pdc_malloc(pdc, (size_t) (sizeof (tt_ushort) * segs), fn);
+
+ if (cm4->numGlyphIds)
+ {
+ cm4->glyphIdArray = (tt_ushort *)
+ pdc_malloc(pdc,
+ (size_t) (sizeof (tt_ushort) * cm4->numGlyphIds), fn);
+ }
+
+ for (i = 0; i < segs; ++i)
+ cm4->endCount[i] = tt_get_ushort(ttf);
+
+ TT_IOCHECK(ttf, cm4->endCount[segs - 1] == 0xFFFF);
+
+ (void) tt_get_ushort(ttf); /* padding */
+ for (i = 0; i < segs; ++i) cm4->startCount[i] = tt_get_ushort(ttf);
+ for (i = 0; i < segs; ++i) cm4->idDelta[i] = tt_get_short(ttf);
+ for (i = 0; i < segs; ++i) cm4->idRangeOffs[i] = tt_get_ushort(ttf);
+
+ for (i = 0; i < cm4->numGlyphIds; ++i)
+ cm4->glyphIdArray[i] = tt_get_ushort(ttf);
+
+ /* empty cmap */
+ if (segs == 1 && cm4->endCount[0] == cm4->startCount[0])
+ {
+ cm4->segCountX2 = 0;
+ pdc_free(pdc, cm4->endCount);
+ cm4->endCount = (tt_ushort *) 0;
+ pdc_free(pdc, cm4->startCount);
+ cm4->startCount = (tt_ushort *) 0;
+ pdc_free(pdc, cm4->idDelta);
+ cm4->idDelta = (tt_short *) 0;
+ pdc_free(pdc, cm4->idRangeOffs);
+ cm4->idRangeOffs = (tt_ushort *) 0;
+ if (cm4->numGlyphIds)
+ {
+ pdc_free(pdc, cm4->glyphIdArray);
+ cm4->glyphIdArray = (tt_ushort *) 0;
+ }
+ }
+
+} /* tt_get_cmap4 */
+
+
+void
+tt_get_tab_cmap(tt_file *ttf)
+{
+ static const char *fn = "tt_get_tab_cmap";
+ pdc_core *pdc = ttf->pdc;
+ tt_tab_cmap *tp = NULL;
+ tt_ulong offset;
+ tt_ushort numEncTabs;
+ tt_ushort platformID = 0;
+ tt_ushort encodingID = 0;
+ tt_ushort tableFormat = 0;
+ tt_ulong offsetEncTab = 0;
+ tt_ulong offset_mac = 0;
+ tt_ulong offset_win = 0;
+ tt_ulong offset_ucs4 = 0;
+ tt_long pos = 0;
+ int i;
+
+ tp = (tt_tab_cmap *) tt_get_tab(ttf, fnt_str_cmap, sizeof (tt_tab_cmap),
+ !ttf->fortet, &offset);
+ if (tp == NULL)
+ return;
+ ttf->tab_cmap = tp;
+
+ tp->win = (tt_cmap4 *) 0;
+ tp->mac = (tt_cmap0_6 *) 0;
+ tp->ucs4 = (tt_cmap12 *) 0;
+
+ tp->platform = 0;
+ tp->encoding = 0;
+ tp->format = 0;
+ tp->offset = 0;
+ tp->length = 0;
+
+ (void) tt_get_ushort(ttf); /* version */
+ numEncTabs = tt_get_ushort(ttf);
+
+ pdc_logg_cond(pdc, 2, trc_font,
+ "\tSearching for cmap table entries:\n");
+ for (i = 0; i < numEncTabs; ++i)
+ {
+ platformID = tt_get_ushort(ttf);
+ encodingID = tt_get_ushort(ttf);
+ offsetEncTab = tt_get_ulong(ttf);
+ pos = tt_tell(ttf);
+
+ tt_seek(ttf, (long) (offset + offsetEncTab));
+ tableFormat = tt_get_ushort(ttf);
+
+ pdc_logg_cond(pdc, 2, trc_font,
+ "\t\tplatformID: %d, encodingID: %2d, "
+ "tableFormat: %2d, offsetEncTab: 0x%04X\n",
+ platformID, encodingID, tableFormat, offsetEncTab);
+
+ /*
+ * platformID: 0 encodingID: 0 tableFormat: 0
+ * platformID: 1 encodingID: 0 tableFormat: 0/6
+ */
+ if (((platformID == tt_pfid_uni && tableFormat == 0) ||
+ platformID == tt_pfid_mac) && encodingID == tt_wenc_symbol)
+ {
+ /* we currently do not support cmaps
+ ** other than format 0 and 6 for Macintosh cmaps.
+ */
+
+ if (tableFormat == 0 && tp->mac == (tt_cmap0_6 *) 0)
+ {
+ tp->mac = (tt_cmap0_6 *)
+ pdc_malloc(pdc, sizeof (tt_cmap0_6), fn);
+ tp->mac->format = 0;
+ tt_get_cmap0(ttf, tp->mac);
+ }
+ else if (tableFormat == 6 && tp->mac == (tt_cmap0_6 *) 0)
+ {
+ tp->mac = (tt_cmap0_6 *)
+ pdc_malloc(pdc, sizeof (tt_cmap0_6), fn);
+ tp->mac->format = 6;
+ tt_get_cmap6(ttf, tp->mac);
+ }
+ offset_mac = offsetEncTab;
+ }
+
+ /*
+ * platformID: 0 encodingID: 3 tableFormat: 4 (old mac)
+ * platformID: 3 encodingID: 0/1 tableFormat: 4
+ */
+ else if ((tp->win == (tt_cmap4 *) 0 && tableFormat == 4) &&
+ ((platformID == tt_pfid_win &&
+ (encodingID == tt_wenc_symbol ||
+ encodingID == tt_wenc_text)) ||
+ (platformID == tt_pfid_uni &&
+ encodingID == tt_wenc_mtext)))
+ {
+ tp->win = (tt_cmap4 *) pdc_malloc(pdc, sizeof (tt_cmap4), fn);
+ tp->win->format = tableFormat;
+
+ /* we suppose a windows platform (see old mac hostfont Times) */
+ if (encodingID == tt_wenc_mtext)
+ {
+ encodingID = tt_wenc_text;
+ }
+
+ tt_get_cmap4(ttf, tp->win);
+
+ if (tp->win->segCountX2)
+ {
+ tp->win->encodingID = encodingID;
+ }
+ else
+ {
+ pdc_free(pdc, tp->win);
+ tp->win = (tt_cmap4 *) 0;
+ }
+ offset_win = offsetEncTab;
+ }
+
+
+ tt_seek(ttf, pos);
+ } /* for */
+
+ /* is symbol font */
+ ttf->issymbol = (tp->win && tp->win->encodingID == tt_wenc_symbol) ?
+ pdc_true : pdc_false;
+
+ /* has Unicode cmap */
+ ttf->haswinuni = (!ttf->issymbol && (tp->win || tp->ucs4)) ?
+ pdc_true : pdc_false;
+
+ /* has only Mac cmap */
+ ttf->hasonlymac = (tp->mac && !tp->win && !tp->ucs4) ?
+ pdc_true : pdc_false;
+
+ if (ttf->hasonlymac)
+ {
+ tp->platform = tt_pfid_mac;
+ tp->encoding = tt_wenc_symbol;
+ tp->format = tp->mac->format;
+ tp->offset = offset_mac;
+ tp->length = tp->mac->length;
+ }
+ else if (tp->win || tp->ucs4)
+ {
+ tp->platform = tt_pfid_win;
+ if (ttf->issymbol)
+ {
+ tp->encoding = tt_wenc_symbol;
+ tp->format = tp->win->format;
+ tp->offset = offset_win;
+ tp->length = tp->win->length;
+ }
+ else if (tp->ucs4)
+ {
+ tp->encoding = tt_wenc_utext;
+ tp->format = tp->ucs4->format;
+ tp->offset = offset_ucs4;
+ tp->length = tp->ucs4->length;
+ }
+ else
+ {
+ tp->encoding = tt_wenc_text;
+ tp->format = tp->win->format;
+ tp->offset = offset_win;
+ tp->length = tp->win->length;
+ }
+ }
+
+ pdc_logg_cond(ttf->pdc, 1, trc_font,
+ "\tUsed cmap table entry:\n"
+ "\t\tplatformID: %d, encodingID: %2d, tableFormat: %2d (%s font)\n",
+ tp->platform, tp->encoding, tp->format,
+ ttf->issymbol ? "symbol" : "text");
+
+ /* for subsetting and symbolic font:
+ * tp->platform = tt_pfid_mac according PDF specification
+ * otherwise GS will emit an error message
+ */
+ if (ttf->issymbol && offset_mac > 0)
+ {
+ tp->platform = tt_pfid_mac;
+ tp->encoding = tt_wenc_symbol;
+ tp->format = tp->mac->format;
+ tp->offset = offset_mac;
+ tp->length = tp->mac->length;
+ }
+
+} /* tt_get_tab_cmap */
+
+void
+tt_get_tab_head(tt_file *ttf)
+{
+ tt_tab_head *tp = NULL;
+
+ tp = (tt_tab_head *) tt_get_tab(ttf, fnt_str_head, sizeof (tt_tab_head),
+ !ttf->fortet, NULL);
+ if (tp == NULL)
+ return;
+ ttf->tab_head = tp;
+
+ tp->version = tt_get_fixed(ttf);
+ tp->fontRevision = tt_get_fixed(ttf);
+ tp->checkSumAdjustment = tt_get_ulong(ttf);
+ tp->magicNumber = tt_get_ulong(ttf);
+ tp->flags = tt_get_ushort(ttf);
+ tp->unitsPerEm = tt_get_ushort(ttf);
+ tp->created[1] = tt_get_ulong(ttf);
+ tp->created[0] = tt_get_ulong(ttf);
+ tp->modified[1] = tt_get_ulong(ttf);
+ tp->modified[0] = tt_get_ulong(ttf);
+ tp->xMin = tt_get_fword(ttf);
+ tp->yMin = tt_get_fword(ttf);
+ tp->xMax = tt_get_fword(ttf);
+ tp->yMax = tt_get_fword(ttf);
+ tp->macStyle = tt_get_ushort(ttf);
+ tp->lowestRecPPEM = tt_get_ushort(ttf);
+ tp->fontDirectionHint = tt_get_short(ttf);
+ tp->indexToLocFormat = tt_get_short(ttf);
+ tp->glyphDataFormat = tt_get_short(ttf);
+} /* tt_get_tab_head */
+
+static void
+tt_get_tab_hhea(tt_file *ttf)
+{
+ tt_tab_hhea *tp = NULL;
+
+ tp = (tt_tab_hhea *) tt_get_tab(ttf, fnt_str_hhea, sizeof (tt_tab_hhea),
+ !ttf->fortet, NULL);
+ if (tp == NULL)
+ return;
+ ttf->tab_hhea = tp;
+
+ tp->version = tt_get_fixed(ttf);
+ tp->ascender = tt_get_fword(ttf);
+ tp->descender = tt_get_fword(ttf);
+ tp->lineGap = tt_get_fword(ttf);
+ tp->advanceWidthMax = tt_get_fword(ttf);
+ tp->minLeftSideBearing = tt_get_fword(ttf);
+ tp->minRightSideBearing = tt_get_fword(ttf);
+ tp->xMaxExtent = tt_get_fword(ttf);
+ tp->caretSlopeRise = tt_get_short(ttf);
+ tp->caretSlopeRun = tt_get_short(ttf);
+ tp->res1 = tt_get_short(ttf);
+ tp->res2 = tt_get_short(ttf);
+ tp->res3 = tt_get_short(ttf);
+ tp->res4 = tt_get_short(ttf);
+ tp->res5 = tt_get_short(ttf);
+ tp->metricDataFormat = tt_get_short(ttf);
+ tp->numberOfHMetrics = tt_get_ushort(ttf);
+} /* tt_get_tab_hhea */
+
+static void
+tt_get_tab_hmtx(tt_file *ttf)
+{
+ static const char *fn = "tt_get_tab_hmtx";
+ pdc_core *pdc = ttf->pdc;
+ tt_tab_hmtx *tp = NULL;
+ int n_metrics;
+ int n_lsbs;
+ int i;
+
+ tp = (tt_tab_hmtx *) tt_get_tab(ttf, fnt_str_hmtx, sizeof (tt_tab_hmtx),
+ !ttf->fortet, NULL);
+ if (tp == NULL)
+ return;
+ ttf->tab_hmtx = tp;
+
+ TT_ASSERT(ttf, ttf->tab_hhea != 0);
+ TT_ASSERT(ttf, ttf->tab_maxp != 0);
+
+ tp->metrics = 0;
+ tp->lsbs = 0;
+
+ n_metrics = ttf->tab_hhea->numberOfHMetrics;
+ n_lsbs = ttf->numGlyphs - n_metrics;
+
+ TT_IOCHECK(ttf, n_metrics != 0);
+ TT_IOCHECK(ttf, n_lsbs >= 0);
+ tp->metrics = (tt_metric *)
+ pdc_malloc(pdc, n_metrics * sizeof (tt_metric), fn);
+
+ for (i = 0; i < n_metrics; ++i)
+ {
+ tp->metrics[i].advanceWidth = tt_get_fword(ttf);
+ tp->metrics[i].lsb = tt_get_fword(ttf);
+ }
+
+ if (n_lsbs == 0)
+ tp->lsbs = (tt_fword *) 0;
+ else
+ {
+ tp->lsbs = (tt_fword *)
+ pdc_malloc(pdc, n_lsbs * sizeof (tt_fword), fn);
+ for (i = 0; i < n_lsbs; ++i)
+ tp->lsbs[i] = tt_get_fword(ttf);
+ }
+} /* tt_get_tab_hmtx */
+
+
+
+pdc_bool
+tt_get_tab_CFF_(tt_file *ttf)
+{
+ static const char *fn = "tt_get_tab_CFF_";
+ pdc_core *pdc = ttf->pdc;
+ int idx = tt_tag2idx(ttf, fnt_str_CFF_);
+
+ if (idx != -1)
+ {
+ /* CFF table found */
+ ttf->tab_CFF_ = (tt_tab_CFF_ *)
+ pdc_malloc(pdc, sizeof (tt_tab_CFF_), fn);
+ ttf->tab_CFF_->offset = ttf->dir[idx].offset;
+ ttf->tab_CFF_->length = ttf->dir[idx].length;
+ }
+ else if (!ttf->fortet)
+ {
+ idx = tt_tag2idx(ttf, fnt_str_glyf);
+ if (idx == -1 || !ttf->dir[idx].length)
+ {
+ pdc_set_errmsg(pdc, FNT_E_TT_NOGLYFDESC, 0, 0, 0, 0);
+ return pdc_false;
+ }
+ idx = -1;
+ }
+
+
+ return pdc_true;
+
+} /* tt_get_tab_CFF_ */
+
+void
+tt_get_tab_maxp(tt_file *ttf)
+{
+ tt_tab_maxp *tp = NULL;
+
+ tp = (tt_tab_maxp *) tt_get_tab(ttf, fnt_str_maxp, sizeof (tt_tab_maxp),
+ !ttf->fortet, NULL);
+ if (tp == NULL)
+ return;
+ ttf->tab_maxp = tp;
+
+ tp->version = tt_get_fixed(ttf);
+ tp->numGlyphs = tt_get_ushort(ttf);
+ tp->maxPoints = tt_get_ushort(ttf);
+ tp->maxContours = tt_get_ushort(ttf);
+ tp->maxCompositePoints = tt_get_ushort(ttf);
+ tp->maxCompositeContours = tt_get_ushort(ttf);
+ tp->maxZones = tt_get_ushort(ttf);
+ tp->maxTwilightPoints = tt_get_ushort(ttf);
+ tp->maxStorage = tt_get_ushort(ttf);
+ tp->maxFunctionDefs = tt_get_ushort(ttf);
+ tp->maxInstructionDefs = tt_get_ushort(ttf);
+ tp->maxStackElements = tt_get_ushort(ttf);
+ tp->maxSizeOfInstructions = tt_get_ushort(ttf);
+ tp->maxComponentElements = tt_get_ushort(ttf);
+ tp->maxComponentDepth = tt_get_ushort(ttf);
+
+ ttf->numGlyphs = tp->numGlyphs;
+
+} /* tt_get_tab_maxp */
+
+pdc_bool
+tt_get_tab_name(tt_file *ttf)
+{
+ static const char *fn = "tt_get_tab_name";
+ pdc_core *pdc = ttf->pdc;
+ pdc_bool logg5 = pdc_logg_is_enabled(pdc, 5, trc_font);
+ tt_tab_name *tp = NULL;
+ int i, j, k, namid, irec, irec4 = -1, irec6 = -1;
+ size_t len;
+ tt_nameref *namerec = NULL, lastnamerec;
+ char *localname = NULL;
+ tt_ulong offset, offs;
+
+ tp = (tt_tab_name *) tt_get_tab(ttf, fnt_str_name, sizeof (tt_tab_name ),
+ pdc_false, &offset);
+ if (tp == NULL)
+ return pdc_false;
+ ttf->tab_name = tp;
+
+ tp->namerecords = NULL;
+ tp->englishname4 = NULL;
+ tp->englishname6 = NULL;
+ tp->producer = NULL;
+
+ tp->format = tt_get_ushort(ttf);
+
+ /* Format 0 is the only document one, but some Apple fonts use 65535.
+ * This is very consequent since it follows Microsoft's lead in
+ * disregarding one's own published specifications.
+ */
+ TT_IOCHECK(ttf, (tp->format == 0 || tp->format == 65535));
+
+ tp->numNameRecords = (tt_ushort)
+ tt_get_offset(ttf, sizeof(tt_ushort));
+ tp->offsetStrings = tt_get_ushort(ttf);
+ offs = offset + tp->offsetStrings;
+
+ pdc_logg_cond(pdc, 1, trc_font,
+ "\tRecords in name table of format %d: %d:\n",
+ tp->format, tp->numNameRecords);
+
+ /* this was observed. we ignore it in TET */
+ if (ttf->fortet && tp->numNameRecords == 0)
+ return pdc_true;
+
+ TT_IOCHECK(ttf, (tp->numNameRecords > 0));
+
+ len = tp->numNameRecords * sizeof (tt_nameref);
+ tp->namerecords = (tt_nameref *) pdc_malloc(pdc, len, fn);
+
+ for (i = 0; i < tp->numNameRecords; ++i)
+ {
+ tt_ushort platformID = tt_get_ushort(ttf);
+ tt_ushort encodingID = tt_get_ushort(ttf);
+ tt_ushort languageID = tt_get_ushort(ttf);
+ tt_ushort nameID = tt_get_ushort(ttf);
+ tt_ushort stringLength = tt_get_ushort(ttf);
+ tt_ushort stringOffset = tt_get_ushort(ttf);
+
+ namerec = &tp->namerecords[i];
+ namerec->platform = platformID;
+ namerec->encoding = encodingID;
+ namerec->language = languageID;
+ namerec->namid = nameID;
+ namerec->length = stringLength;
+ namerec->offset = stringOffset;
+ }
+
+ namid = 4;
+ for (k = 0; k < 2; k++)
+ {
+ lastnamerec.platform = 0;
+ lastnamerec.language = 0;
+ lastnamerec.namid = 0;
+ lastnamerec.length = 0;
+ lastnamerec.offset = 0;
+
+ for (i = 0; i < tp->numNameRecords; ++i)
+ {
+ localname = NULL;
+ namerec = &tp->namerecords[i];
+
+ if (logg5 && !k)
+ {
+ pdc_logg(pdc, "\t\t\t%2d. platformID: %d\n"
+ "\t\t\t encodingID: %d\n"
+ "\t\t\t languageID: %d\n"
+ "\t\t\t nameID: %d\n"
+ "\t\t\t length: %d\n"
+ "\t\t\t offset: %d\n",
+ i,
+ namerec->platform, namerec->encoding,
+ namerec->language, namerec->namid,
+ namerec->length, namerec->offset);
+
+ /* read font name */
+ if (namerec->length)
+ {
+ localname =
+ (char *) pdc_calloc(pdc, (size_t) namerec->length, fn);
+ tt_seek(ttf, (long) (offs + namerec->offset));
+ tt_read(ttf, localname, (unsigned int) namerec->length);
+
+ pdc_logg_hexdump(pdc, "data", "\t\t\t ",
+ localname, namerec->length);
+ }
+ pdc_logg(pdc, "\n");
+ }
+
+ if (tp->producer == NULL &&
+ namerec->platform == tt_pfid_mac &&
+ namerec->encoding == tt_wenc_symbol &&
+ namerec->language == 0 &&
+ namerec->namid == 0)
+ {
+ tp->producer = (char *) pdc_calloc(pdc,
+ (size_t) namerec->length + 1, fn);
+ tt_seek(ttf, (long) (offs + namerec->offset));
+ tt_read(ttf, tp->producer, (unsigned int) namerec->length);
+ }
+
+ if (namerec->length && namerec->namid == namid)
+ {
+ /* TTC font search */
+ if (ttf->utf16fontname)
+ {
+ /* read font name */
+ if (localname == NULL)
+ {
+ localname = (char *) pdc_calloc(pdc,
+ (size_t) namerec->length, fn);
+ tt_seek(ttf, (long) (offs + namerec->offset));
+ tt_read(ttf, localname, (unsigned int) namerec->length);
+ }
+
+ if (namerec->platform == tt_pfid_win)
+ {
+ pdc_logg_cond(pdc, 1, trc_font,
+ "\tUnicode fontname: \"%T\"\n",
+ localname, namerec->length);
+
+ if (namerec->length == ttf->fnamelen &&
+ !memcmp(localname, ttf->utf16fontname,
+ (size_t) ttf->fnamelen))
+ {
+ /* font found */
+ pdc_free(pdc, localname);
+ return pdc_true;
+ }
+ }
+ }
+
+ /* search for the records with english names */
+ else
+ {
+ /* we take the names from platformID 3 (Microsoft) or
+ * 1 (Macintosh). We favor Macintosh and then Microsoft
+ * with American English (LanguageID = 0x0409 = 1033)
+ */
+ if ((lastnamerec.language != 0x0409 ||
+ lastnamerec.platform != tt_pfid_win) &&
+ (namerec->platform == tt_pfid_win ||
+ (namerec->platform == tt_pfid_mac &&
+ namerec->language == 0)))
+ {
+ lastnamerec = *namerec;
+
+ /* We simulate always English */
+ if (namerec->platform == tt_pfid_mac)
+ lastnamerec.language = 0x0409;
+
+ if (namid == 4) irec4 = i;
+ if (namid == 6) irec6 = i;
+ }
+ }
+ }
+
+ if (localname != NULL)
+ pdc_free(pdc, localname);
+ }
+ namid = 6;
+ }
+
+ /* TTC font not found */
+ if (ttf->utf16fontname)
+ return pdc_false;
+
+ /* English font names */
+ namid = 4;
+ irec = irec4;
+ for (k = 0; k < 2; k++)
+ {
+ if (irec == -1)
+ continue;
+ namerec = &tp->namerecords[irec];
+
+ /* read font name */
+ len = (size_t) (namerec->length + 1);
+ localname = (char *) pdc_calloc(pdc, (size_t) len, fn);
+ tt_seek(ttf, (long) (offs + namerec->offset));
+ tt_read(ttf, localname, (unsigned int) namerec->length);
+
+ /* low byte picking */
+ if (namerec->platform == tt_pfid_win)
+ {
+ for (j = 0; j < namerec->length / 2; j++)
+ {
+ /* We don't support wide character names */
+ if (localname[2*j] != 0)
+ {
+ pdc_free(pdc, localname);
+ localname = NULL;
+ break;
+ }
+ localname[j] = localname[2*j + 1];
+ }
+ if (localname)
+ localname[j] = 0;
+ }
+
+ /* We observed this in EUDC fonts */
+ if (localname && !strcmp(localname, "\060\060"))
+ {
+ pdc_free(pdc, localname);
+ localname = NULL;
+ }
+
+ if (namid == 4 && localname)
+ tp->englishname4 = localname;
+ else if (namid == 6 && localname)
+ tp->englishname6 = localname;
+
+ namid = 6;
+ irec = irec6;
+ }
+
+ /* font name 4 (full font name) is required */
+ if (tp->englishname6 == NULL && tp->englishname4 == NULL)
+ {
+ if (!ttf->fortet)
+ {
+ pdc_set_errmsg(pdc, FNT_E_TT_NONAME, 0, 0, 0, 0);
+ return pdc_false;
+ }
+ }
+ else
+ {
+ if (tp->englishname4 == NULL)
+ tp->englishname4 = pdc_strdup(pdc, tp->englishname6);
+ if (tp->englishname6 == NULL)
+ tp->englishname6 = pdc_strdup(pdc, tp->englishname4);
+ }
+
+ return pdc_true;
+} /* tt_get_tab_name */
+
+static int tt_cpflag2cp[64] =
+{
+ 1252, 1250, 1251, 1253, 1254, 1255, 1256, 1257,
+ 1258, 0, 0, 0, 0, 0, 0, 0,
+ 874, 932, 936, 949, 950, 1361, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 869, 866, 865, 864, 863, 862, 861, 860,
+ 857, 855, 852, 775, 737, 708, 850, 437
+};
+
+static int tt_cpflag2charcoll[4] =
+{
+ cc_japanese, cc_simplified_chinese, cc_korean, cc_traditional_chinese
+};
+
+void
+tt_get_tab_OS_2(tt_file *ttf)
+{
+ pdc_bool logg3 = pdc_logg_is_enabled(ttf->pdc, 3, trc_font);
+ int i, j;
+
+ tt_tab_OS_2 *tp = NULL;
+
+ tp = (tt_tab_OS_2 *) tt_get_tab(ttf, fnt_str_OS_2, sizeof (tt_tab_OS_2),
+ pdc_false, NULL);
+ if (tp == NULL)
+ return;
+ ttf->tab_OS_2 = tp;
+
+ tp->version = tt_get_ushort(ttf);
+ tp->xAvgCharWidth = tt_get_short(ttf);
+ tp->usWeightClass = tt_get_ushort(ttf);
+ tp->usWidthClass = tt_get_ushort(ttf);
+ tp->fsType = tt_get_ushort(ttf);
+ tp->ySubscriptXSize = tt_get_short(ttf);
+ tp->ySubscriptYSize = tt_get_short(ttf);
+ tp->ySubscriptXOffset = tt_get_short(ttf);
+ tp->ySubscriptYOffset = tt_get_short(ttf);
+ tp->ySuperscriptXSize = tt_get_short(ttf);
+ tp->ySuperscriptYSize = tt_get_short(ttf);
+ tp->ySuperscriptXOffset = tt_get_short(ttf);
+ tp->ySuperscriptYOffset = tt_get_short(ttf);
+ tp->yStrikeoutSize = tt_get_short(ttf);
+ tp->yStrikeoutPosition = tt_get_short(ttf);
+ tp->sFamilyClass = tt_get_ushort(ttf);
+
+ tt_read(ttf, tp->panose, 10);
+
+ tp->ulUnicodeRange1 = tt_get_ulong(ttf);
+ tp->ulUnicodeRange2 = tt_get_ulong(ttf);
+ tp->ulUnicodeRange3 = tt_get_ulong(ttf);
+ tp->ulUnicodeRange4 = tt_get_ulong(ttf);
+
+ tt_read(ttf, tp->achVendID, 4);
+
+ tp->fsSelection = tt_get_ushort(ttf);
+ tp->usFirstCharIndex = tt_get_ushort(ttf);
+ tp->usLastCharIndex = tt_get_ushort(ttf);
+ tp->sTypoAscender = tt_get_short(ttf);
+ tp->sTypoDescender = tt_get_short(ttf);
+ tp->sTypoLineGap = tt_get_short(ttf);
+ tp->usWinAscent = tt_get_ushort(ttf);
+ tp->usWinDescent = tt_get_ushort(ttf);
+
+ if (tp->version >= 1)
+ {
+ tp->ulCodePageRange1 = tt_get_ulong(ttf);
+ tp->ulCodePageRange2 = tt_get_ulong(ttf);
+ }
+ else
+ {
+ tp->ulCodePageRange1 = 0;
+ tp->ulCodePageRange2 = 0;
+ }
+
+ for (i = 0; i < PDC_NUMCHARCOLL; i++)
+ {
+ j = i + 17;
+ if (tp->ulCodePageRange1 & (1<<j))
+ tp->charcolls[i] = tt_cpflag2charcoll[i];
+ else
+ tp->charcolls[i] = cc_none;
+ }
+
+ if (tp->version >= 2)
+ {
+ tp->sxHeight = tt_get_short(ttf);
+ tp->sCapHeight = tt_get_short(ttf);
+ tp->usDefaultChar = tt_get_ushort(ttf);
+ tp->usBreakChar = tt_get_ushort(ttf);
+ tp->usMaxContext = tt_get_ushort(ttf);
+ }
+ else
+ {
+ tp->sxHeight = FNT_MISSING_FONTVAL;
+ tp->sCapHeight = FNT_MISSING_FONTVAL;
+ tp->usDefaultChar = 0;
+ tp->usBreakChar = 0;
+ tp->usMaxContext = 0;
+ }
+
+ /* there are fonts with inconsistent usFirstCharIndex */
+ if (ttf->tab_cmap && ttf->tab_cmap->win &&
+ tp->usFirstCharIndex != ttf->tab_cmap->win->startCount[0])
+ ttf->tab_OS_2->usFirstCharIndex = ttf->tab_cmap->win->startCount[0];
+
+ if (logg3)
+ {
+ int nbit = 8 * sizeof(tt_ulong);
+
+ pdc_logg_bitarr(ttf->pdc, "\t\tulUnicodeRange1 ",
+ (char *) &tp->ulUnicodeRange1, nbit);
+ pdc_logg_bitarr(ttf->pdc, "\t\tulUnicodeRange2 ",
+ (char *) &tp->ulUnicodeRange2, nbit);
+ pdc_logg_bitarr(ttf->pdc, "\t\tulUnicodeRange3 ",
+ (char *) &tp->ulUnicodeRange3, nbit);
+ pdc_logg_bitarr(ttf->pdc, "\t\tulUnicodeRange4 ",
+ (char *) &tp->ulUnicodeRange4, nbit);
+
+ if (tp->version >= 1)
+ {
+ int n = 0;
+
+ pdc_logg_bitarr(ttf->pdc, "\t\tulCodePageRange1",
+ (char *) &tp->ulCodePageRange1, nbit);
+ pdc_logg_bitarr(ttf->pdc, "\t\tulCodePageRange2",
+ (char *) &tp->ulCodePageRange2, nbit);
+
+ for (i = 0; i < 32; i++)
+ {
+ if ((tp->ulCodePageRange1 & (1<<i)) && tt_cpflag2cp[i])
+ {
+ pdc_logg(ttf->pdc, "%s%d",
+ (n ? ", " : "\t\tsupported code pages: "),
+ tt_cpflag2cp[i]);
+ n++;
+ }
+ }
+ for (i = 0; i < 32; i++)
+ {
+ j = i + 32;
+ if ((tp->ulCodePageRange1 & (1<<i)) && tt_cpflag2cp[j])
+ {
+ pdc_logg(ttf->pdc, "%s%d",
+ (n ? ", " : "\t\tsupported code pages: "),
+ tt_cpflag2cp[j]);
+ n++;
+ }
+ }
+
+ if (n)
+ pdc_logg(ttf->pdc, "\n");
+
+ n = 0;
+ for (i = 0; i < PDC_NUMCHARCOLL; i++)
+ {
+ if (tp->charcolls[i])
+ {
+ pdc_logg(ttf->pdc, "%s%s",
+ (n ? ", " : "\t\tsupported character collections: "),
+ fnt_get_ordering_cid(tp->charcolls[i]));
+ n++;
+ }
+ }
+ if (n)
+ pdc_logg(ttf->pdc, "\n");
+ }
+ }
+} /* tt_get_tab_OS_2 */
+
+
+static void
+tt_get_tab_post(tt_file *ttf)
+{
+ tt_tab_post *tp = NULL;
+
+
+ tp = (tt_tab_post *) tt_get_tab(ttf, fnt_str_post, sizeof (tt_tab_post),
+ !ttf->fortet, NULL);
+ if (tp == NULL)
+ return;
+ ttf->tab_post = tp;
+
+ tp->formatType = tt_get_fixed(ttf);
+ tp->italicAngle = (tt_get_fixed(ttf) / 65536.0);
+ tp->underlinePosition = tt_get_fword(ttf);
+ tp->underlineThickness = tt_get_fword(ttf);
+ tp->isFixedPitch = tt_get_ulong(ttf);
+ tp->minMemType42 = tt_get_ulong(ttf);
+ tp->maxMemType42 = tt_get_ulong(ttf);
+ tp->minMemType1 = tt_get_ulong(ttf);
+ tp->maxMemType1 = tt_get_ulong(ttf);
+
+
+} /* tt_get_tab_post */
+
+
+
+/*--------------------------- general functions ------------------------------*/
+
+#define FNT_O ((char) 0x4f) /* ASCII 'O' */
+#define FNT_T ((char) 0x54) /* ASCII 'T' */
+
+#define FNT_t ((char) 0x74) /* ASCII 't' */
+#define FNT_r ((char) 0x72) /* ASCII 'r' */
+#define FNT_u ((char) 0x75) /* ASCII 'u' */
+#define FNT_e ((char) 0x65) /* ASCII 'e' */
+
+#define FNT_c ((char) 0x63) /* ASCII 'c' */
+#define FNT_f ((char) 0x66) /* ASCII 'f' */
+
+static const char *fnt_filetypes[4] =
+{
+ "TrueType", "OpenType", "Apple TrueType", "TrueType Collection"
+};
+
+pdc_bool
+fnt_test_tt_font(pdc_core *pdc, tt_byte *img, tt_ulong *n_fonts,
+ pdc_bool requested)
+{
+ tt_ushort n_tables;
+ int ift = 0;
+ pdc_bool retval = requested ? pdc_false : pdc_undef;
+
+ /* The TrueType (including OpenType/TT) "version" is always 0x00010000 */
+ if (!(img[0] == 0x00 && img[1] == 0x01 &&
+ img[2] == 0x00 && img[3] == 0x00))
+ {
+ ift++;
+
+ /* The OpenType/CFF version is always 'OTTO' */
+ if (!(img[0] == FNT_O && img[1] == FNT_T &&
+ img[2] == FNT_T && img[3] == FNT_O))
+ {
+ ift++;
+
+ /* Old Apple fonts have 'true' */
+ if (!(img[0] == FNT_t && img[1] == FNT_r &&
+ img[2] == FNT_u && img[3] == FNT_e))
+ {
+ ift++;
+
+ /* TrueType Collection */
+ if (n_fonts == NULL ||
+ !(img[0] == FNT_t && img[1] == FNT_t &&
+ img[2] == FNT_c && img[3] == FNT_f))
+ return retval;
+
+ /* Version is always 0x00010000 or 0x00020000 */
+ if (!(img[4] == 0x00 && (img[5] == 0x01 || img[5] == 0x02) &&
+ img[6] == 0x00 && img[7] == 0x00))
+ return retval;
+
+ /* Number of fonts */
+ *n_fonts = pdc_get_be_ulong(&img[8]);
+
+ pdc_logg_cond(pdc, 1, trc_font,
+ "\t%s font with %d single fonts detected\n",
+ fnt_filetypes[ift], *n_fonts);
+
+ return pdc_true;
+ }
+ }
+ }
+
+ /* Number of tables */
+ n_tables = pdc_get_be_ushort(&img[4]);
+ if (n_tables < 8 && n_tables > 64) /* max. 32 tables ? */
+ return retval;
+
+ /* Further check of the next 6 bytes not implemented */
+
+ if (n_fonts == NULL)
+ pdc_logg_cond(pdc, 1, trc_font,
+ "\t%s font with %d tables detected\n",
+ fnt_filetypes[ift], n_tables);
+
+ return pdc_true;
+}
+
+pdc_bool
+fnt_is_opentype_font(tt_file *ttf)
+{
+ return (ttf->img[0] == FNT_O &&
+ ttf->img[1] == FNT_T &&
+ ttf->img[2] == FNT_T &&
+ ttf->img[3] == FNT_O) ? pdc_true : pdc_false;
+}
+
+pdc_bool
+fnt_read_offset_tab(tt_file *ttf)
+{
+ static const char *fn = "fnt_get_tab_offset";
+ pdc_core *pdc = ttf->pdc;
+ tt_byte img[TT_OFFSETTAB_SIZE];
+ int i;
+
+ /* Check */
+ tt_read(ttf, img, TT_OFFSETTAB_SIZE);
+ if (fnt_test_tt_font(pdc, img, NULL, pdc_true) == pdc_false)
+ {
+ pdc_set_errmsg(pdc, FNT_E_TT_NOFONT, ttf->filename, 0, 0, 0);
+ return pdc_false;
+ }
+
+ /* number of table directories */
+ ttf->n_tables = pdc_get_be_ushort(&img[4]);
+
+ /* set up table directory */
+ ttf->dir = (tt_dirent *) pdc_malloc(pdc,
+ (size_t) (ttf->n_tables * sizeof (tt_dirent)), fn);
+
+ tt_seek(ttf, (long) (ttf->offset + TT_OFFSETTAB_SIZE));
+
+ for (i = 0; i < ttf->n_tables; ++i)
+ {
+ tt_get_dirent(ttf->dir + i, ttf);
+ }
+
+ /* make sure this isn't a bitmap-only Mac font */
+ if (tt_tag2idx(ttf, fnt_str_bhed) != -1)
+ {
+ pdc_set_errmsg(pdc, FNT_E_TT_BITMAP, 0, 0, 0, 0);
+ return pdc_false;
+ }
+
+ return pdc_true;
+
+} /* fnt_read_offset_tab */
+
+pdc_bool
+fnt_read_tt(tt_file *ttf)
+{
+ pdc_core *pdc = ttf->pdc;
+
+ PDC_TRY(pdc)
+ {
+ if (fnt_read_offset_tab(ttf) == pdc_false)
+ {
+ PDC_EXIT_TRY(pdc);
+ return pdc_false;
+ }
+
+ /* These are all required TrueType tables;
+ * optional tables are not read.
+ */
+ tt_get_tab_cmap(ttf);
+ tt_get_tab_head(ttf);
+ tt_get_tab_hhea(ttf);
+ tt_get_tab_maxp(ttf);
+ if (!ttf->fortet)
+ tt_get_tab_hmtx(ttf); /* MUST be read AFTER hhea & maxp! */
+ if (tt_get_tab_name(ttf) == pdc_false && !ttf->fortet)
+ {
+ PDC_EXIT_TRY(pdc);
+ return pdc_false;
+ }
+ tt_get_tab_post(ttf);
+ tt_get_tab_OS_2(ttf); /* may be missing from some Apple fonts */
+
+ /* this is an optional table, present only in OpenType fonts */
+ if (tt_get_tab_CFF_(ttf) == pdc_false && !ttf->fortet)
+ {
+ PDC_EXIT_TRY(pdc);
+ return pdc_false;
+ }
+
+
+ PDC_EXIT_TRY(pdc);
+ return pdc_true;
+ }
+ PDC_CATCH(pdc)
+ {
+ }
+
+ return pdc_false;
+} /* fnt_read_tt */
+
+
+
+/* convert Unicode scalar to glyph ID using cmap12 or cmap4.
+ */
+int
+tt_unicode2gidx(tt_file *ttf, int usv, pdc_bool logg)
+{
+ pdc_core *pdc = ttf->pdc;
+ tt_cmap4 *cm4 = ttf->tab_cmap->win;
+ pdc_ushort uv;
+ int segs;
+ int gidx = 0;
+ int i;
+
+ uv = (pdc_ushort) usv;
+ if (logg) pdc_logg(pdc, "\t\t\tU+%04X: ", uv);
+ segs = cm4->segCountX2 / 2;
+
+ for (i = 0; i < segs; ++i)
+ if (uv <= cm4->endCount[i])
+ break;
+
+ if (logg) pdc_logg(pdc, "i=%d start=U+%04X ", i, cm4->startCount[i]);
+
+ TT_IOCHECK(ttf, i != segs);
+ if (uv < cm4->startCount[i] || uv == 0xFFFF)
+ {
+ if (logg) pdc_logg(pdc, "==> gidx=0\n");
+ return 0;
+ }
+
+ if (logg) pdc_logg(pdc, "offs=%d ", cm4->idRangeOffs[i]);
+
+ if (cm4->idRangeOffs[i] == 0)
+ {
+ if (logg) pdc_logg(pdc, "delta=%d ", cm4->idDelta[i]);
+ gidx = (int)((uv + cm4->idDelta[i]) & 0xFFFF);
+ }
+ else
+ {
+ int idx = (int) cm4->idRangeOffs[i] / 2
+ + (int) (uv - cm4->startCount[i]) - (segs - i);
+
+ if (idx < 0 || idx >= cm4->numGlyphIds)
+ {
+ pdc_warning(pdc, FNT_E_TT_GLYPHIDNOTFOUND,
+ pdc_errprintf(pdc, "%04X", uv),
+ 0, 0, 0);
+ return 0;
+ }
+
+ if (logg) pdc_logg(pdc, "array[%d]=%d ", idx, gidx);
+ if (cm4->glyphIdArray[idx] == 0)
+ {
+ if (logg) pdc_logg(pdc, "==> gidx=0\n");
+ return 0;
+ }
+ else
+ {
+ if (logg) pdc_logg(pdc, "delta=%d ", cm4->idDelta[i]);
+ gidx = (int)((cm4->glyphIdArray[idx] + cm4->idDelta[i]) & 0xFFFF);
+ }
+ }
+
+ if (logg) pdc_logg(pdc, "gidx=%d ", gidx);
+
+ /* this is necessary because of some Mac fonts (e.g. Hiragino) */
+ if (gidx >= ttf->numGlyphs)
+ {
+ gidx = 0;
+ if (logg) pdc_logg(pdc, "==> gidx=0\n");
+ }
+ else if (logg)
+ pdc_logg(pdc, "\n");
+
+ return gidx;
+}
+
+int
+tt_gidx2width(tt_file *ttf, int gidx)
+{
+ TT_ASSERT(ttf, ttf->tab_hmtx != (tt_tab_hmtx *) 0);
+ TT_ASSERT(ttf, ttf->tab_hhea != (tt_tab_hhea *) 0);
+
+ {
+ int n_metrics = ttf->tab_hhea->numberOfHMetrics;
+
+ if (gidx >= n_metrics)
+ gidx = n_metrics - 1;
+ if (ttf->monospace)
+ return ttf->monospace;
+ else
+ {
+ return FNT_TT2PDF(ttf->tab_hmtx->metrics[gidx].advanceWidth);
+ }
+ }
+} /* tt_gidx2width */
+
+void
+fnt_set_tt_fontvalues(tt_file *ttf)
+{
+ fnt_font *font = ttf->font;
+ fnt_font_metric *ftm = &font->m;
+
+ if (ttf->onlyCFF)
+ return;
+
+ if (ttf->tab_head)
+ {
+ ftm->llx = FNT_TT2PDF(ttf->tab_head->xMin);
+ ftm->lly = FNT_TT2PDF(ttf->tab_head->yMin);
+ ftm->urx = FNT_TT2PDF(ttf->tab_head->xMax);
+ ftm->ury = FNT_TT2PDF(ttf->tab_head->yMax);
+ }
+
+ if (ttf->tab_post)
+ {
+ ftm->italicAngle = ttf->tab_post->italicAngle;
+ ftm->isFixedPitch = (pdc_bool) ttf->tab_post->isFixedPitch;
+ ftm->underlinePosition = FNT_TT2PDF(ttf->tab_post->underlinePosition);
+ ftm->underlineThickness =FNT_TT2PDF(ttf->tab_post->underlineThickness);
+ }
+
+ if (ttf->tab_OS_2)
+ {
+
+ font->weight = fnt_check_weight(ttf->tab_OS_2->usWeightClass);
+ ftm->ascender = FNT_TT2PDF(ttf->tab_OS_2->sTypoAscender);
+ ftm->descender = FNT_TT2PDF(ttf->tab_OS_2->sTypoDescender);
+
+ if (ttf->tab_OS_2->sCapHeight != FNT_MISSING_FONTVAL)
+ ftm->capHeight = FNT_TT2PDF(ttf->tab_OS_2->sCapHeight);
+ if (ttf->tab_OS_2->sxHeight != FNT_MISSING_FONTVAL)
+ ftm->xHeight = FNT_TT2PDF(ttf->tab_OS_2->sxHeight);
+ font->linegap = FNT_TT2PDF(ttf->tab_OS_2->sTypoLineGap);
+ }
+
+ /* some fonts have no OS/2 table and
+ * some Apple fonts have zero values in the OS/2 table .
+ */
+ if (ttf->tab_OS_2 == NULL ||
+ (ttf->tab_OS_2->usWeightClass == 0 &&
+ ttf->tab_OS_2->sTypoAscender == 0 &&
+ ttf->tab_OS_2->sTypoDescender == 0 &&
+ ttf->tab_OS_2->sTypoLineGap == 0))
+ {
+ font->weight = fnt_macfontstyle2weight(ttf->tab_head->macStyle);
+ ftm->ascender = FNT_TT2PDF(ttf->tab_hhea->ascender);
+ ftm->descender = FNT_TT2PDF(ttf->tab_hhea->descender);
+ font->linegap = FNT_TT2PDF(ttf->tab_hhea->lineGap);
+ }
+
+ /* default width */
+ if (!ttf->fortet)
+ {
+ ftm->defwidth = tt_gidx2width(ttf, 0);
+ }
+}
+
+
+/*
+ * Create and fill some arrays in font structure.
+ *
+ * Before calling function the members 'encoding' and 'ev'
+ * of font struct have to been set:
+ *
+ * The desired arrays must be requested by following flags
+ * (enc == font->enc):
+ *
+ * TT_FONT_encvec: Encoding vector (enc == pdc_builtin)
+ *
+ * TT_FONT_gid2code: font->gid2code[font->numglyphs]:
+ * glyph ID -> 8-bit code (enc >= 0, == pdc_builtin)
+ * glyph ID -> Unicode otherwise.
+ *
+ * TT_FONT_code2gid: font->code2gid[font->numcodes]:
+ * 8-bit code -> glyph ID (enc >= 0, == pdc_builtin)
+ * Unicode -> glyph ID (enc == pdc_unicode)
+ * glyph ID -> glyph ID (enc == pdc_glyphid)
+ *
+ * TT_FONT_gid2name font->gdi2name[font->numglyphs]:
+ * glyph ID -> glyph name (enc == pdc_glyphid only)
+ *
+ * TT_FONT_name2unitab font->name2unitab[font->tabsize]:
+ * glyph name -> Unicode for unregistered names
+ *
+ * TT_FONT_m_ciw font->m.ciw[font->m.numinters] (Interval table)
+ * Unicode -> glyph width (enc == pdc_unicode only)
+ *
+ * TT_FONT_m_widths font->m.widths[font->numcodes]
+ * 8-bit code -> glyph width (enc >= 0, == pdc_builtin)
+ * glyph ID -> glyph width (enc == pdc_glyphid)
+ *
+ * TT_FONT_names font->m.name = englishname4
+ * font->name = englishname6
+ */
+int
+fnt_set_tt_fontarrays(tt_file *ttf, int flags)
+{
+ static const char *fn = "pdc_set_tt_fontarrays";
+ pdc_core *pdc = ttf->pdc;
+ fnt_font *font = ttf->font;
+ pdc_bool logg2 = pdc_logg_is_enabled(pdc, 2, trc_font);
+ pdc_bool logg5 = pdc_logg_is_enabled(pdc, 5, trc_font);
+ pdc_bool logg7 = pdc_logg_is_enabled(pdc, 7, trc_font);
+ pdc_encoding enc = font->enc, encb = pdc_invalidenc;
+ pdc_encodingvector *ev = NULL, *evb = NULL;
+ const char *glyphname;
+ pdc_bool regorder, isencbyte = pdc_false;
+ pdc_ushort uc, uv;
+ int ncodes = 0, gidx = 0, width = 0, foundglyphs = 0, uvoffset = 0;
+ int ucoffset = 0;
+ int code;
+
+ /* Unicode offset for symbol fonts */
+ if (ttf->issymbol == pdc_true)
+ {
+ if (ttf->tab_OS_2)
+ {
+ /* e.g. WingDings has usFirstChar = 0xF020, but we must start
+ ** at 0xF000. I haven't seen non-symbol fonts with a usFirstChar
+ ** like that; perhaps we have to apply similar tricks then...
+ */
+ uvoffset = (ttf->tab_OS_2->usFirstCharIndex & 0xFF00);
+ }
+ else
+ {
+ /* This would be an Apple font with an encoding different
+ * from macroman or a subset font withot OS_2 table.
+ */
+ if (!ttf->fortet)
+ {
+ pdc_set_errmsg(pdc, FNT_E_TT_SYMBOLOS2, 0, 0, 0, 0);
+ return -1;
+ }
+ uvoffset = 0xF000;
+ }
+
+ if (logg7)
+ pdc_logg(pdc, "\t\t\tuvoffset: U+%04X\n", uvoffset);
+ }
+
+ /* font names */
+ if (flags & TT_FONT_names && ttf->tab_name)
+ {
+ font->m.name = pdc_strdup(pdc, ttf->tab_name->englishname4);
+ font->name = pdc_strdup(pdc, ttf->tab_name->englishname6);
+ }
+
+ /* is Standard Latin font */
+ font->issymbfont = ttf->issymbol;
+
+ /* number of glyphs */
+ font->numglyphs = ttf->numGlyphs;
+
+ /* number of codes */
+ switch(enc)
+ {
+ case pdc_cid:
+ case pdc_unicode:
+ font->numcodes = ttf->numunicode;
+ break;
+
+ case pdc_glyphid:
+ font->numcodes = font->numglyphs;
+ break;
+
+ default:
+ font->numcodes = 256;
+ ev = pdc_get_encoding_vector(pdc, enc);
+ isencbyte = pdc_true;
+ break;
+ }
+
+
+ if (enc < 0 && ttf->hasonlymac)
+ {
+ encb = pdc_macroman;
+ evb = pdc_get_encoding_vector(pdc, encb);
+ }
+ else
+ {
+ encb = enc;
+ evb = ev;
+
+ if (flags & TT_FONT_encvec && enc == pdc_builtin)
+ {
+ evb = fnt_create_font_ev(pdc, font);
+ ev = evb;
+ }
+ }
+
+ if (flags & TT_FONT_code2gid)
+ {
+ if (ttf->numunicode <= PDC_NUM_BMPVAL || isencbyte ||
+ enc == pdc_glyphid)
+ {
+ font->code2gid = (pdc_ushort *) pdc_calloc(pdc,
+ font->numcodes * sizeof (pdc_ushort), fn);
+ }
+ }
+
+ if ((flags & TT_FONT_gid2code) || logg2)
+ {
+ if (ttf->numunicode <= PDC_NUM_BMPVAL || isencbyte)
+ {
+ font->gid2code = (pdc_ushort *) pdc_calloc(pdc,
+ font->numglyphs * sizeof (pdc_ushort), fn);
+ }
+ }
+
+
+ if (flags & TT_FONT_m_widths)
+ {
+ font->m.numwidths = font->numcodes;
+ font->m.widths = (int *) pdc_calloc(pdc,
+ font->m.numwidths * sizeof(int), fn);
+ }
+
+
+ /*
+ * Build the char width tables for the font, set mappings GID <-> Code,
+ * and count the characters.
+ */
+ foundglyphs = 0;
+ regorder = pdc_true;
+ ncodes = (enc == pdc_glyphid) ? ttf->numunicode : font->numcodes;
+ for (code = 0; code < ncodes; code++)
+ {
+ uc = (pdc_ushort) code;
+ uv = 0;
+ gidx = 0;
+
+
+ if (encb == pdc_macroman && ttf->tab_cmap->mac)
+ {
+ tt_cmap0_6 *cm = ttf->tab_cmap->mac;
+
+ if (code > -1 && code < (int) (cm->firstCode + cm->entryCount))
+ gidx = cm->glyphIdArray[code];
+ }
+ else if (ttf->issymbol == pdc_true)
+ {
+ switch (encb)
+ {
+ case pdc_unicode:
+ if (!ttf->fortet)
+ {
+ if (code < 0x00FF)
+ {
+ /* we map the lower Unicode values too */
+ if (uvoffset > 0x00FF)
+ regorder = pdc_false;
+ uv = (pdc_ushort) (code + uvoffset);
+ break;
+ }
+ regorder = pdc_true;
+ }
+
+ case pdc_glyphid:
+ uv = (pdc_ushort) code;
+ break;
+
+ default:
+ {
+ uv = (pdc_ushort) (code + uvoffset);
+ }
+ if (evb != NULL)
+ evb->codes[code] = uv;
+ break;
+ }
+
+ if (!gidx)
+ gidx = tt_unicode2gidx(ttf, (int) uv, logg7);
+ }
+ else
+ {
+ uv = evb->codes[code];
+ if (uv)
+ {
+ gidx = tt_unicode2gidx(ttf, (int) uv, logg7);
+ }
+ }
+
+ /*
+ * Mapping GID -> [Uni]code
+ * This is a 1:n relation (e.g. 1 -> SPACE, 1 -> NBSP)
+ * We prefer the first occurence (SPACE) (regorder),
+ * in the case of TT symbol fonts the second occurence.
+ */
+ if (gidx && regorder && uc >= ucoffset)
+ {
+ /* mapping gid -> code */
+ if (font->gid2code)
+ {
+ if (!font->gid2code[gidx])
+ {
+ font->gid2code[gidx] = uc;
+ if (logg5)
+ pdc_logg(pdc, "\t\tGID: %d -> U+%04X\n",
+ gidx, font->gid2code[gidx]);
+ }
+ else if (logg2)
+ {
+ pdc_logg(pdc, "\t\tGID: %d: U+%04X vs. U+%04X\n",
+ gidx, font->gid2code[gidx], uc);
+ }
+ }
+ foundglyphs++;
+
+ }
+
+ switch (enc)
+ {
+
+ default:
+ if (font->m.numwidths)
+ font->m.widths[code] = tt_gidx2width(ttf, gidx);
+ break;
+ }
+
+ /* mapping code -> gid */
+ if (font->code2gid)
+ {
+ font->code2gid[code] = (pdc_ushort) gidx;
+ if (logg5 && gidx)
+ pdc_logg(pdc, "\t\tU+%04X -> GID: %d\n",
+ code, font->code2gid[code]);
+ }
+ }
+
+
+ /* logging protocol and/or to check the completeness
+ * of the glyph names
+ */
+ if (logg2
+ )
+ {
+ if (logg2)
+ pdc_logg(pdc,
+ "\n\t\tGlyph mapping for %d glyphs:\n", ttf->numGlyphs);
+
+ width = -1;
+ for (gidx = 0; gidx < ttf->numGlyphs; gidx++)
+ {
+ pdc_bool fontspecific = pdc_false;
+ glyphname = NULL;
+
+
+ code = fnt_get_code(gidx, font);
+ if (!ttf->fortet)
+ width = tt_gidx2width(ttf, gidx);
+
+ if (code >= 0 && glyphname == NULL)
+ {
+ if (enc >= 0 || (ttf->issymbol && ev != NULL))
+ glyphname = ev->chars[code];
+ else if (enc != pdc_builtin && code <= 0xFFFF)
+ glyphname = (char *) pdc_unicode2glyphname(pdc,
+ (pdc_ushort) code);
+ }
+
+ pdc_logg(pdc, "\t\tGID%5d: ", gidx);
+ if (!ttf->fortet)
+ pdc_logg(pdc, "width=%4d ", width);
+
+ switch (enc)
+ {
+
+ default:
+ if (!gidx || code > 0)
+ {
+ if (enc >= 0 || (ttf->issymbol && ev != NULL))
+ {
+ uv = ev->codes[code];
+ pdc_logg(pdc, "code=%3d U+%04X ", code, uv);
+ }
+ else
+ {
+ if (ttf->fortet && enc == pdc_builtin)
+ pdc_logg(pdc, "U+%04X ", code);
+ else
+ pdc_logg(pdc, "code=%3d ", code);
+ }
+ }
+ break;
+ }
+ if (glyphname != NULL)
+ pdc_logg(pdc, "\"%s\"", glyphname);
+ if (fontspecific)
+ pdc_logg(pdc, " (specific)");
+ pdc_logg(pdc, "\n");
+ }
+ }
+
+ if (!(flags & TT_FONT_gid2code))
+ {
+ if (ttf->numunicode <= PDC_NUM_BMPVAL && font->gid2code != NULL)
+ {
+ pdc_free(pdc, font->gid2code);
+ font->gid2code = NULL;
+ }
+ }
+
+ return foundglyphs;
+}
+
+pdc_encoding
+fnt_get_tt_encoding_key(tt_file *ttf, pdc_encoding inenc)
+{
+ pdc_encoding outenc = inenc;
+
+ /* Symbol font */
+ if (ttf->issymbol && inenc >= pdc_winansi)
+ outenc = pdc_builtin;
+
+ /* MacRoman font */
+ if (ttf->hasonlymac && inenc >= pdc_builtin)
+ outenc = pdc_macroman;
+
+ if (!ttf->issymbol && !ttf->haswinuni && !ttf->hasonlymac)
+ {
+ outenc = pdc_invalidenc;
+ pdc_logg_cond(ttf->pdc, 1, trc_font,
+ "\tTrueType font contains %s cmap table\n",
+ ttf->tab_cmap ? "unsupported" : "no" );
+ }
+ else
+ {
+ pdc_logg_cond(ttf->pdc, 1, trc_font,
+ "\tEncoding \"%s\" will be determined\n",
+ pdc_get_user_encoding(ttf->pdc, outenc));
+ }
+
+ return outenc;
+}
+
+static pdc_bool
+fnt_check_and_read_ttc(pdc_core *pdc, pdc_file *fp,
+ const char *filename, const char *fontname,
+ fnt_font *font, tt_ulong n_fonts)
+{
+ static const char *fn = "fnt_check_and_read_ttc";
+ const char *sf;
+ tt_file *ttf;
+ pdc_byte *utf16fontname = NULL;
+ pdc_bool retval = pdc_false;
+ pdc_text_format textformat = PDC_UTF8;
+ pdc_text_format targettextformat = pdc_utf16be;
+ int i, inlen, outlen;
+ int ift = -1;
+
+ /* initialize */
+ ttf = fnt_new_tt(pdc, font);
+ ttf->filename = filename;
+ ttf->fontname = fontname;
+ ttf->check = pdc_true;
+ ttf->fp = fp;
+ ttf->verbose = pdc_false;
+
+ /* searching for font index in font name */
+ sf = strrchr(fontname, ':');
+ if (sf != NULL)
+ {
+ sf++;
+ if (!*sf)
+ ift = 0;
+ else if (pdc_str2integer(sf, PDC_INT_UNSIGNED, &i))
+ ift = i;
+ }
+
+ /* create UTF-16-BE font name string for searching in font file */
+ if (ift == -1)
+ {
+ inlen = (int) strlen(font->utf8name);
+ if (pdc_convert_string(pdc, textformat, 0, NULL,
+ (pdc_byte *) font->utf8name, inlen,
+ &targettextformat, NULL,
+ &utf16fontname, &outlen,
+ PDC_CONV_NOBOM | PDC_CONV_INFLATE, ttf->verbose))
+ {
+ goto FNT_TRUETYPE_EXIT;
+ }
+ }
+
+ /* search font */
+ for (i = 0; i < (int)n_fonts; ++i)
+ {
+ if (i) fnt_delete_tt(ttf);
+
+ tt_seek(ttf, (long) (TT_OFFSETTAB_SIZE + i * sizeof(tt_ulong)));
+ ttf->offset = tt_get_ulong(ttf);
+ tt_seek(ttf, (long) ttf->offset);
+
+ pdc_logg_cond(pdc, 1, trc_font, "\tChecking font #%d \n", i+1);
+
+ /* Offset Table */
+ if (!fnt_read_offset_tab(ttf))
+ goto FNT_TRUETYPE_EXIT;
+
+ /* font name match in Naming Table */
+ if (ift > -1)
+ {
+ if (ift == i)
+ break;
+ }
+ else
+ {
+ /* font name match in Naming Table */
+ if (utf16fontname == NULL)
+ break;
+ ttf->utf16fontname = (char *) utf16fontname;
+ ttf->fnamelen = outlen;
+ if (tt_get_tab_name(ttf))
+ break;
+ }
+ }
+ if (utf16fontname != NULL)
+ pdc_free(pdc, utf16fontname);
+
+ /* font found */
+ if (i < (int)n_fonts)
+ {
+ tt_byte *pos;
+ tt_ulong headlen, dirlen, tablen, length, offset;
+
+ /* create file in memory */
+ tablen = 0;
+ dirlen = 4 * sizeof(tt_ulong);
+ headlen = (tt_ulong) (TT_OFFSETTAB_SIZE + ttf->n_tables * dirlen);
+ font->filelen = headlen;
+ for (i = 0; i < ttf->n_tables; i++)
+ {
+ length = ttf->dir[i].length;
+ if (length > tablen) tablen = length;
+ font->filelen += length;
+ }
+ font->img = (pdc_byte *) pdc_malloc(pdc, font->filelen, fn);
+
+ /* read font file */
+ tt_seek( ttf, (long) ttf->offset);
+ tt_read( ttf, font->img, headlen);
+ pos = font->img + headlen;
+ for (i = 0; i < ttf->n_tables; i++)
+ {
+ length = ttf->dir[i].length;
+ tt_seek( ttf, (long) ttf->dir[i].offset);
+ tt_read( ttf, pos, length);
+ ttf->dir[i].offset = (unsigned int) (pos - font->img);
+ pos += length;
+ }
+
+ /* correct offsets in Table Directory */
+ pos = font->img + TT_OFFSETTAB_SIZE + 2 * sizeof(tt_ulong);
+ for (i = 0; i < ttf->n_tables; i++)
+ {
+ offset = ttf->dir[i].offset;
+ pos[0] = (tt_byte) (offset >> 24);
+ pos[1] = (tt_byte) (offset >> 16);
+ pos[2] = (tt_byte) (offset >> 8);
+ pos[3] = (tt_byte) (offset);
+ pos += dirlen;
+ }
+ retval = pdc_true;
+ }
+ else
+ {
+ pdc_set_errmsg(pdc, FNT_E_TTC_NOTFOUND, filename, 0, 0, 0);
+ goto FNT_TRUETYPE_EXIT;
+ }
+
+ FNT_TRUETYPE_EXIT:
+
+ ttf->check = pdc_false;
+ fnt_delete_tt(ttf);
+
+ return retval;
+}
+
+pdc_bool
+fnt_check_tt_font(pdc_core *pdc, const char *filename, const char *fontname,
+ fnt_font *font, pdc_bool requested)
+{
+ pdc_file *fp;
+ char fullname[PDC_FILENAMELEN];
+ tt_byte img[TT_OFFSETTAB_SIZE];
+ pdc_bool ismem = pdc_false;
+ tt_ulong n_fonts = 0;
+ int retval = requested ? pdc_false : pdc_undef;
+
+ fp = pdc_fsearch_fopen(pdc, filename, fullname, "font ",PDC_FILE_BINARY);
+ if (fp != NULL)
+ {
+ if (PDC_OK_FREAD(fp, img, TT_OFFSETTAB_SIZE))
+ {
+ pdc_logg_cond(pdc, 1, trc_font,
+ "\tLoading TrueType fontfile \"%s\":\n", fullname);
+
+ retval = fnt_test_tt_font(pdc, img, &n_fonts, requested);
+ if (retval == pdc_true)
+ {
+ ismem = pdc_file_isvirtual(fp);
+
+ if (fontname != NULL)
+ {
+ if (n_fonts > 1)
+ {
+ retval = fnt_check_and_read_ttc(pdc, fp, filename,
+ fontname, font, n_fonts);
+ fp = NULL;
+ }
+ else
+ {
+ font->img = (pdc_byte *)
+ pdc_freadall(fp, &font->filelen, NULL);
+ }
+
+ if (retval == pdc_true)
+ {
+ if (font->filelen == 0)
+ {
+ pdc_set_errmsg(pdc,
+ PDC_E_IO_READ, fullname, 0, 0, 0);
+ retval = pdc_false;
+ }
+ }
+ }
+
+ if (retval == pdc_true)
+ {
+ if (fp != NULL && ismem)
+ {
+ font->imgname = pdc_strdup(pdc, filename);
+ pdc_lock_pvf(pdc, font->imgname);
+ }
+
+ font->filename = pdc_strdup(pdc, fullname);
+ }
+ }
+ }
+
+ if (fp != NULL)
+ pdc_fclose(fp);
+ }
+ else
+ {
+ retval = pdc_check_fopen_errmsg(pdc, requested);
+ }
+
+ return retval;
+}
+
+
+/*
+ * After fnt_new_tt initialize following members
+ * (here with the opposite of default):
+ *
+ * ttf->filename = filename;
+ * ttf->fontname = fontname;
+ *
+ * ttf->verbose = pdc_false;
+ * ttf->kerning = pdc_true;
+ * ttf->vertical = pdc_true;
+ * ttf->fortet = pdc_true;
+ *
+ * ttf->check = pdc_true;
+ * ttf->incore = pdc_true;
+ * ttf->savecff = pdc_true;
+ * ttf->monospace = 1000;
+ *
+ * ttf->fp = fp;
+ *
+ */
+tt_file *
+fnt_new_tt(pdc_core *pdc, fnt_font *font)
+{
+ static const char *fn = "fnt_new_tt";
+
+ tt_file *ttf = (tt_file *)
+ pdc_malloc(pdc, (size_t) sizeof (tt_file), fn);
+
+ ttf->pdc = pdc;
+ ttf->font = font;
+
+ ttf->img = (tt_byte *) font->img;
+ ttf->pos = ttf->img;
+ ttf->end = ttf->img + font->filelen;
+
+ ttf->filename = NULL;
+ ttf->fontname = NULL;
+ ttf->verbose = pdc_true;
+ ttf->fortet = pdc_false;
+ ttf->check = pdc_false;
+ ttf->incore = pdc_false;
+ ttf->savecff = pdc_false;
+ ttf->monospace = 0;
+ ttf->fp = NULL;
+
+ ttf->n_tables = 0;
+ ttf->offset = 0;
+ ttf->dir = (tt_dirent *) 0;
+
+ ttf->tab_cmap = (tt_tab_cmap *) 0;
+ ttf->tab_head = (tt_tab_head *) 0;
+ ttf->tab_hhea = (tt_tab_hhea *) 0;
+ ttf->tab_hmtx = (tt_tab_hmtx *) 0;
+ ttf->tab_maxp = (tt_tab_maxp *) 0;
+ ttf->tab_name = (tt_tab_name *) 0;
+ ttf->tab_post = (tt_tab_post *) 0;
+ ttf->tab_OS_2 = (tt_tab_OS_2 *) 0;
+ ttf->tab_CFF_ = (tt_tab_CFF_ *) 0;
+
+ ttf->numGlyphs = 0;
+ ttf->onlyCFF = 0;
+ ttf->hasGlyphNames = 0;
+ ttf->numunicode = PDC_NUM_BMPVAL;
+ ttf->builtinenc = pdc_stdenc;
+ ttf->regisadobe = pdc_false;
+ ttf->charcoll = cc_none;
+ ttf->supplement = 0;
+
+ ttf->issymbol = pdc_false;
+ ttf->haswinuni = pdc_false;
+ ttf->hasonlymac = pdc_false;
+
+
+ ttf->utf16fontname = (char *) 0;
+ ttf->fnamelen = 0;
+
+ return ttf;
+
+} /* fnt_new_tt */
+
+void
+fnt_delete_tt(tt_file *ttf)
+{
+ pdc_core *pdc = ttf->pdc;
+ int i;
+
+ (void) i;
+
+ if (ttf->check == pdc_false && ttf->fp != (pdc_file *) 0)
+ pdc_fclose(ttf->fp);
+
+ if (ttf->dir != (tt_dirent *) 0)
+ pdc_free(pdc, ttf->dir);
+ ttf->dir = (tt_dirent *) 0;
+
+
+ if (ttf->tab_head != (tt_tab_head *) 0)
+ pdc_free(pdc, ttf->tab_head);
+ if (ttf->tab_hhea != (tt_tab_hhea *) 0)
+ pdc_free(pdc, ttf->tab_hhea);
+ if (ttf->tab_maxp != (tt_tab_maxp *) 0)
+ pdc_free(pdc, ttf->tab_maxp);
+ if (ttf->tab_OS_2 != (tt_tab_OS_2 *) 0)
+ pdc_free(pdc, ttf->tab_OS_2);
+ if (ttf->tab_CFF_ != (tt_tab_CFF_ *) 0)
+ pdc_free(pdc, ttf->tab_CFF_);
+ if (ttf->tab_post != (tt_tab_post *) 0)
+ {
+ pdc_free(pdc, ttf->tab_post);
+ }
+
+ if (ttf->tab_cmap != (tt_tab_cmap *) 0)
+ {
+ if (ttf->tab_cmap->mac != (tt_cmap0_6 *) 0) {
+ if (ttf->tab_cmap->mac->glyphIdArray)
+ pdc_free(pdc, ttf->tab_cmap->mac->glyphIdArray);
+ pdc_free(pdc, ttf->tab_cmap->mac);
+ }
+
+ if (ttf->tab_cmap->win != (tt_cmap4 *) 0)
+ {
+ tt_cmap4 *cm4 = (tt_cmap4 *) ttf->tab_cmap->win;
+
+ if (cm4->endCount != 0) pdc_free(pdc, cm4->endCount);
+ if (cm4->startCount != 0) pdc_free(pdc, cm4->startCount);
+ if (cm4->idDelta != 0) pdc_free(pdc, cm4->idDelta);
+ if (cm4->idRangeOffs != 0) pdc_free(pdc, cm4->idRangeOffs);
+ if (cm4->glyphIdArray != 0) pdc_free(pdc, cm4->glyphIdArray);
+
+ pdc_free(pdc, cm4);
+ }
+
+ if (ttf->tab_cmap->ucs4 != (tt_cmap12 *) 0)
+ {
+ tt_cmap12 *cm12 = (tt_cmap12 *) ttf->tab_cmap->ucs4;
+
+ if (cm12->grouptab != 0) pdc_free(pdc, cm12->grouptab);
+
+ pdc_free(pdc, cm12);
+ }
+
+ pdc_free(pdc, ttf->tab_cmap);
+ }
+
+ if (ttf->tab_hmtx != (tt_tab_hmtx *) 0)
+ {
+ if (ttf->tab_hmtx->metrics != (tt_metric *) 0)
+ pdc_free(pdc, ttf->tab_hmtx->metrics);
+ if (ttf->tab_hmtx->lsbs != (tt_fword *) 0)
+ pdc_free(pdc, ttf->tab_hmtx->lsbs);
+ pdc_free(pdc, ttf->tab_hmtx);
+ }
+
+ if (ttf->tab_name != (tt_tab_name *) 0)
+ {
+ if (ttf->tab_name->namerecords != (tt_nameref *) 0)
+ pdc_free(pdc, ttf->tab_name->namerecords);
+ if (ttf->tab_name->englishname4 != (char *) 0)
+ pdc_free(pdc, ttf->tab_name->englishname4);
+ if (ttf->tab_name->englishname6 != (char *) 0)
+ pdc_free(pdc, ttf->tab_name->englishname6);
+ if (ttf->tab_name->producer != (char *) 0)
+ pdc_free(pdc, ttf->tab_name->producer);
+ pdc_free(pdc, ttf->tab_name);
+ }
+ ttf->tab_name = (tt_tab_name *) 0;
+
+
+ /* Note: do not clean up ttf->img since the data belongs to font->img
+ */
+
+ if (ttf->check == pdc_false)
+ pdc_free(pdc, ttf);
+
+} /* fnt_delete_tt */
+
+
+#endif /* PDF_TRUETYPE_SUPPORTED */