summaryrefslogtreecommitdiff
path: root/Build/source/texk/xdvik/ft.c
diff options
context:
space:
mode:
authorPeter Breitenlohner <peb@mppmu.mpg.de>2013-04-08 06:34:46 +0000
committerPeter Breitenlohner <peb@mppmu.mpg.de>2013-04-08 06:34:46 +0000
commit7e0f3484d8cd6eca4abe80d057391d14face5606 (patch)
tree92570fc98a476ecbf696c2ef16d046412d405995 /Build/source/texk/xdvik/ft.c
parent824f7b0903de8ad7f6ee3d7656005e4c59155e06 (diff)
xdvik 22.86
git-svn-id: svn://tug.org/texlive/trunk@29732 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/xdvik/ft.c')
-rw-r--r--Build/source/texk/xdvik/ft.c484
1 files changed, 484 insertions, 0 deletions
diff --git a/Build/source/texk/xdvik/ft.c b/Build/source/texk/xdvik/ft.c
new file mode 100644
index 00000000000..74ef96786e4
--- /dev/null
+++ b/Build/source/texk/xdvik/ft.c
@@ -0,0 +1,484 @@
+/*========================================================================*\
+
+Copyright (c) 2013 Paul Vojta
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+\*========================================================================*/
+
+/*
+ * FreeType (PostScript Type 1 and TrueType) font reading routines.
+ * Public routines are load_ft_font and read_ft_char.
+ * The prototype for load_ft_font is in dvi-init.h.
+ */
+
+#include "xdvi-config.h"
+#include "xdvi.h"
+#include "dvi-init.h"
+#include "dvi-draw.h"
+#include "util.h"
+#include "font-open.h"
+
+#include <ctype.h>
+#include <math.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_SIZES_H
+
+static FT_Library library = NULL;
+
+static struct avl_enc *enc_head = NULL;
+
+/* From xc/lib/X11/PutImage.c */
+
+#if !WORDS_BIGENDIAN
+static const unsigned char reverse_byte[0x100] = {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+#endif /* !WORDS_BIGENDIAN */
+
+
+/*
+ * FreeType I/O stream functions
+ */
+
+static unsigned long
+xdvi_stream_read(FT_Stream stream,
+ unsigned long offset,
+ unsigned char *buffer,
+ unsigned long count)
+{
+ struct font *fontp;
+
+ fontp = ((struct ftfont *) stream->descriptor.pointer)->first_size;
+ open_font_file(fontp);
+ fseek(fontp->file, offset, SEEK_SET);
+ return (unsigned long) fread(buffer, 1, count, fontp->file);
+}
+
+static void
+xdvi_stream_close(FT_Stream stream)
+{
+ /* do nothing */
+}
+
+
+/*
+ * Public routines
+ */
+
+static void
+read_ft_char(struct font *fontp, wide_ubyte ch)
+{
+ struct glyph *g;
+ FT_Face face;
+ FT_GlyphSlot slot;
+ int bmTypeT_wide;
+ int err;
+
+ if (globals.debug & DBG_PK)
+ printf("Loading FreeType char %d", ch);
+
+ /*
+ * Load it unscaled first, so that we can get a more accurate
+ * (non-hinted) value of the horizontal advance.
+ */
+
+ g = &fontp->glyph[ch];
+ face = fontp->ft->face;
+ FT_Activate_Size(fontp->size);
+ err = FT_Load_Glyph(face, g->addr, FT_LOAD_NO_SCALE);
+ if (err != 0)
+ XDVI_FATAL((stderr, "FT_Load_Glyph: error = %d", err));
+
+ g->dvi_adv = face->glyph->metrics.horiAdvance * fontp->ft->expn
+ * fontp->pixsize * (1 << 16) / face->units_per_EM + 0.5;
+
+ /* Now do the real loading. */
+
+ err = FT_Load_Glyph(face, g->addr, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);
+ if (err != 0)
+ XDVI_FATAL((stderr, "FT_Load_Glyph: error = %d", err));
+
+ slot = face->glyph;
+ g->bitmap.w = slot->bitmap.width;
+ g->bitmap.h = slot->bitmap.rows;
+
+ if (globals.debug & DBG_PK)
+ printf(", size=%dx%d, dvi_adv=%ld\n", g->bitmap.w, g->bitmap.h,
+ g->dvi_adv);
+
+ alloc_bitmap(&g->bitmap);
+ bmTypeT_wide = ROUNDUP((int) g->bitmap.w, BMBITS);
+
+ if (slot->bitmap.width > 0) {
+ int i;
+ unsigned char *p;
+ bmUnitT *q;
+
+ p = slot->bitmap.buffer;
+ q = (bmUnitT *) g->bitmap.bits;
+ for (i = g->bitmap.h; i > 0; --i) {
+#if WORDS_BIGENDIAN
+ memcpy(q, p, (slot->bitmap.width + 7) / 8);
+#else
+ unsigned char *p1 = p;
+ bmUnitT *q1 = q;
+ bmUnitT data = 0;
+ int shift = 0;
+ int j;
+
+ for (j = (slot->bitmap.width + 7) / 8; j > 0; --j) {
+ if (shift >= BMBITS) {
+ *q1++ = data;
+ data = 0;
+ shift = 0;
+ }
+ data |= reverse_byte[*p1++] << shift;
+ shift += 8;
+ }
+ *q1 = data;
+#endif
+ p += slot->bitmap.pitch;
+ q += bmTypeT_wide;
+ }
+ }
+
+ /* The offset of (-1,-1) is from comparing bitmaps of 'R' and 'a'
+ between cmr10.pfb and cmr10.300pk. */
+ g->x = -1 - slot->bitmap_left;
+ g->y = slot->bitmap_top - 1;
+}
+
+/*
+ * Do the ScaleFont, etc. directives.
+ */
+
+static Boolean
+set_transform(struct ftfont *ftp,
+ const char *str)
+{
+ double x = 1.0;
+ double y = 0.0;
+
+ for (;;) {
+ while (isspace(*str)) ++str;
+ if (*str == '\0')
+ break;
+
+ if (isdigit(*str) || *str == '.' || *str == '-') {
+ double arg = strtod(str, (char **) &str);
+
+ while (isspace(*str)) ++str;
+
+ if (memcmp(str, "ObliqueSlant", 12) == 0
+ && (isspace(str[12]) || str[12] == '\0')) {
+ arg = -tan(arg);
+ str += 12;
+ while (isspace(*str)) ++str;
+ }
+
+ if (memcmp(str, "SlantFont", 9) == 0
+ && (isspace(str[9]) || str[9] == '\0')) {
+ y += arg;
+ str += 9;
+ }
+ else if (memcmp(str, "ExtendFont", 10) == 0
+ && (isspace(str[10]) || str[10] == '\0')) {
+ x *= arg;
+ str += 10;
+ }
+ else return False;
+ }
+ else { /* other characters; presume encoding name */
+ while (!isspace(*str) && *str != '\0') ++str;
+ while (isspace(*str)) ++str;
+ if (memcmp(str, "ReEncodeFont", 12) == 0
+ && (isspace(str[12]) || str[12] == '\0'))
+ str += 12;
+ else
+ return False;
+ }
+ }
+
+ if (x != 1.0 || y != 0.0) {
+ FT_Matrix mat;
+
+ mat.xx = (FT_Fixed) (x * 0x10000 + 0.5);
+ mat.xy = (FT_Fixed) (y * 0x10000 + 0.5);
+ mat.yx = 0;
+ mat.yy = 0x10000;
+
+ FT_Set_Transform(ftp->face, &mat, NULL);
+ ftp->expn = x;
+ }
+
+ return True;
+}
+
+
+/*
+ * When a document uses many freetype fonts, it can take a while to read
+ * them all (due mostly to disk access issues). So, we delay loading
+ * freetype fonts until they're needed.
+ *
+ * Therefore, this routine is not called until it is time to render a
+ * character from the font (see set_ft_char() in dvi-draw.c).
+ *
+ * It loads and sets up the font.
+ */
+
+Boolean
+load_ft_font(struct font *fontp)
+{
+ struct ftfont *ftp;
+ struct avl_t1 *t1p;
+ struct font *fontp2;
+ FT_Face face;
+ FT_Size size;
+ int err;
+ const char *path;
+ FILE *f;
+
+ ftp = fontp->ft;
+ t1p = ftp->t1;
+ fontp2 = ftp->first_size;
+
+ if (!resource.freetype) {
+ TRACE_FT((stderr,
+ "load_ft_font returning: freetype has been turned off"));
+ return False;
+ }
+
+ if (t1p->bad) {
+ TRACE_FT((stderr, "Font %s was flagged as bad; skipping (size %d)",
+ fontp->fontname, (int) (fontp->fsize + 0.5)));
+ return False;
+ }
+
+ face = ftp->face;
+ if (face != NULL) { /* if this face is already in use */
+ err = FT_New_Size(face, &size);
+ if (err != 0) {
+ /* This error is probably better kept at stderr instead of
+ a popup (too annoying) or the statusline (might disappear
+ too fast) ... */
+ XDVI_ERROR((stderr, "Could not load FreeType font %s at %d: "
+ "FreeType FT_New_Size error = %d.\n"
+ "Will try pixel version instead.\n"
+ "Please see the FreeType documentation for details "
+ "about this.",
+ fontp->fontname, (int) (fontp->fsize + 0.5), err));
+ return False;
+ }
+ }
+ else {
+ FT_Open_Args args;
+
+ f = open_t1_font(t1p, &path);
+ if (f == NULL)
+ return False;
+
+ if (library == NULL) {
+ err = FT_Init_FreeType(&library);
+ if (err != 0) {
+ XDVI_ERROR((stderr,
+ "Could not initialize FreeType library: "
+ "FreeType FT_Init_FreeType error = %d.\n"
+ "Turning off use of FreeType.\n"
+ "Please see the FreeType documentation for details "
+ "about this.",
+ err));
+ resource.freetype = False;
+ free((char *) path);
+ fclose(f);
+ return False;
+ }
+ }
+
+ fontp2->filename = path;
+ fontp2->file = f;
+
+ fseek(f, 0L, SEEK_END);
+ ftp->stream.size = ftell(f);
+ fseek(f, 0L, SEEK_SET); /* this might not be necessary */
+
+ ftp->stream.descriptor.pointer = ftp;
+ ftp->stream.read = xdvi_stream_read;
+ ftp->stream.close = xdvi_stream_close;
+
+ args.flags = FT_OPEN_STREAM;
+ args.stream = &ftp->stream;
+ err = FT_Open_Face(library, &args, 0, &face);
+ if (err != 0) {
+ /* This error is probably better kept at stderr instead of
+ a popup (too annoying) or the statusline (might disappear
+ too fast) ... */
+ XDVI_ERROR((stderr, "Could not load FreeType font %s: "
+ "FreeType FT_Open_Face error = %d.\n"
+ "Will try pixel version instead.\n"
+ "Please see the FreeType documentation for details "
+ "about this.",
+ fontp->fontname, err));
+ free((char *) path);
+ fclose(f);
+ fontp2->file = NULL;
+ fontp2->filename = NULL;
+ return False;
+ }
+ ftp->face = face;
+
+ if (!FT_IS_SCALABLE(face)) {
+ TRACE_FT((stderr, "Font %s is not scalable.", fontp->fontname));
+ FT_Done_Face(face);
+ free((char *) path);
+ fclose(f);
+ fontp2->file = NULL;
+ fontp2->filename = NULL;
+ return False;
+ }
+
+ ftp->expn = 1.0;
+ if (t1p->addinfo != NULL)
+ if (!set_transform(ftp, t1p->addinfo)) {
+ FT_Done_Face(face);
+ free((char *) path);
+ fclose(f);
+ fontp2->file = NULL;
+ fontp2->filename = NULL;
+ return False;
+ }
+
+ if (face->charmap == NULL) {
+ if (face->num_charmaps > 0) {
+ if ((globals.debug & DBG_PK) && face->num_charmaps > 1)
+ printf("Choosing the first of %d charmaps.\n",
+ face->num_charmaps);
+ }
+ FT_Set_Charmap(face, face->charmaps[0]);
+ }
+ else if (face->charmap->encoding == ft_encoding_unicode
+ && FT_Select_Charmap(face, ft_encoding_adobe_custom) != 0
+ && FT_Select_Charmap(face, ft_encoding_adobe_standard) != 0
+ && FT_Select_Charmap(face, ft_encoding_adobe_expert) != 0) {
+ if (globals.debug & DBG_PK)
+ puts("Using unicode charmap for font.");
+ fputs("Using unicode charmap\n", stderr); /* ||| */
+ }
+
+ ftp->enc = NULL;
+ if (t1p->encname != NULL) { /* if there's an encoding */
+ struct avl_enc *encp;
+
+ encp = (struct avl_enc *) avladd(t1p->encname,
+ strlen(t1p->encname),
+ (struct avl **) &enc_head, sizeof *encp);
+ if (encp->key == t1p->encname) /* if new record */
+ read_encoding(encp);
+ if (encp->valid)
+ ftp->enc = encp;
+ }
+
+ size = face->size;
+ }
+
+ /* Get character indices (store them in addr) */
+
+ if (globals.debug & DBG_PK)
+ printf("Character indices for %s:\n", fontp->fontname);
+
+ FT_Activate_Size(size);
+
+ err = FT_Set_Char_Size(face,
+ (int) (fontp->pixsize * (72<<6) / resource.pixels_per_inch + 0.5), 0,
+ resource.pixels_per_inch, resource.pixels_per_inch);
+ if (err != 0)
+ XDVI_FATAL((stderr, "FT_Set_Char_Size: error = %d\n", err));
+
+ /* Look for already-computed character indices */
+ for (fontp2 = ftp->first_size;; fontp2 = fontp2->next_size) {
+ int i;
+
+ if (fontp2 == NULL) { /* if not found */
+ struct avl_enc *encp = ftp->enc;
+
+ for (i = 0; i < 256; ++i) {
+ int ci;
+
+ if (encp == NULL)
+ ci = FT_Get_Char_Index(face, i);
+ else {
+ const char *glyphname = encp->vec[i];
+
+ if (glyphname == NULL)
+ ci = 0;
+ else
+ ci = FT_Get_Name_Index(face,
+ (FT_String *) glyphname);
+ }
+
+ fontp->glyph[i].addr = ci;
+ if (globals.debug & DBG_PK)
+ printf("%3d->%3d%s", i, ci, (i + 1) % 8 ? " " : "\n");
+ }
+ break;
+ }
+ if (fontp2->size != NULL) { /* found the information */
+ for (i = 0; i < 256; ++i)
+ fontp->glyph[i].addr = fontp2->glyph[i].addr;
+ break;
+ }
+ }
+
+ fontp->size = size; /* it needed to be NULL in the above loop */
+ fontp->read_char = read_ft_char;
+
+ return True;
+}