summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/xetexdir/XeTeXFontInst.cpp
diff options
context:
space:
mode:
authorKhaled Hosny <khaledhosny@eglug.org>2013-03-06 22:43:23 +0000
committerKhaled Hosny <khaledhosny@eglug.org>2013-03-06 22:43:23 +0000
commit2fb851202b1da73113b967586b130f59ee5491dd (patch)
treea85b08eb844b14e9b567c8cb73752ac40019c9c9 /Build/source/texk/web2c/xetexdir/XeTeXFontInst.cpp
parent6eaf934f7aad57a32b0166d28dabff1fccf151d6 (diff)
Sync XeTeX
git-svn-id: svn://tug.org/texlive/trunk@29299 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/xetexdir/XeTeXFontInst.cpp')
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeXFontInst.cpp457
1 files changed, 339 insertions, 118 deletions
diff --git a/Build/source/texk/web2c/xetexdir/XeTeXFontInst.cpp b/Build/source/texk/web2c/xetexdir/XeTeXFontInst.cpp
index 837640d1d48..fb214097de4 100644
--- a/Build/source/texk/web2c/xetexdir/XeTeXFontInst.cpp
+++ b/Build/source/texk/web2c/xetexdir/XeTeXFontInst.cpp
@@ -41,176 +41,381 @@ authorization from the copyright holders.
#include "XeTeXFontInst.h"
#include "XeTeXLayoutInterface.h"
-#include "XeTeXswap.h"
-
#include "XeTeX_ext.h"
-#include "sfnt.h"
-
#include <string.h>
+#include FT_GLYPH_H
+#include FT_ADVANCES_H
+FT_Library gFreeTypeLibrary = 0;
+// FT_LOAD_NO_BITMAP is needed to work around:
+// http://lists.gnu.org/archive/html/freetype/2013-03/msg00009.html
+static int ftLoadFlags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP;
-XeTeXFontInst::XeTeXFontInst(float pointSize, int &status)
+XeTeXFontInst::XeTeXFontInst(const char* pathname, int index, float pointSize, int &status)
: fPointSize(pointSize)
, fUnitsPerEM(0)
, fAscent(0)
, fDescent(0)
+ , fCapHeight(0)
+ , fXHeight(0)
, fItalicAngle(0)
- , fMetricsTable(NULL)
- , fNumLongMetrics(0)
- , fNumGlyphs(0)
- , fNumGlyphsInited(false)
, fVertical(false)
, fFilename(NULL)
+ , ftFace(0)
, hbFont(NULL)
+ , fMath(NULL)
{
- // the concrete subclass is responsible to call initialize()
+ if (pathname != NULL)
+ initialize(pathname, index, status);
}
XeTeXFontInst::~XeTeXFontInst()
{
- if (fMetricsTable != NULL)
- deleteTable(fMetricsTable);
+ if (ftFace != 0) {
+ FT_Done_Face(ftFace);
+ ftFace = 0;
+ }
+ hb_font_destroy(hbFont);
}
-void XeTeXFontInst::initialize(int &status)
-{
- const HEADTable *headTable = NULL;
- const HHEATable *dirHeadTable = NULL;
- const POSTTable *postTable = NULL;
-
- // dispose of any cached metrics table
- if (fMetricsTable != NULL) {
- deleteTable(fMetricsTable);
- fMetricsTable = NULL;
- }
-
- // read unitsPerEm from 'head' table
- headTable = (const HEADTable *) readFontTable(kHEAD);
+/* HarfBuzz font functions */
- if (headTable == NULL) {
- status = 1;
- goto error_exit;
- }
+static hb_bool_t
+_get_glyph(hb_font_t*, void *font_data, hb_codepoint_t ch, hb_codepoint_t vs, hb_codepoint_t *gid, void*)
+{
+ FT_Face face = (FT_Face) font_data;
+ *gid = 0;
- fUnitsPerEM = SWAP(headTable->unitsPerEm);
- deleteTable(headTable);
+ if (vs)
+ *gid = FT_Face_GetCharVariantIndex (face, ch, vs);
- // we use the fact that 'hhea' and 'vhea' have the same format!
- dirHeadTable = (const HHEATable *) readFontTable(fVertical ? kVHEA : kHHEA);
+ if (*gid == 0)
+ *gid = FT_Get_Char_Index (face, ch);
- if (dirHeadTable == NULL) {
- status = 1;
- goto error_exit;
- }
+ return *gid != 0;
+}
- fAscent = unitsToPoints((float)(int16_t)SWAP(dirHeadTable->ascent));
- fDescent = unitsToPoints((float)(int16_t)SWAP(dirHeadTable->descent));
+static FT_Fixed
+_get_glyph_advance(FT_Face face, FT_UInt gid, bool vertical)
+{
+ FT_Error error;
+ FT_Fixed advance;
+ int flags = ftLoadFlags;
- fNumLongMetrics = SWAP(dirHeadTable->numOfLongHorMetrics);
+ if (vertical)
+ flags |= FT_LOAD_VERTICAL_LAYOUT;
- deleteTable(dirHeadTable);
+ error = FT_Get_Advance(face, gid, ftLoadFlags, &advance);
+ if (error)
+ advance = 0;
+ else
+ advance = advance >> 10;
- postTable = (const POSTTable *) readFontTable(kPOST);
+ return advance;
+}
- if (postTable != NULL) {
- fItalicAngle = Fix2D(SWAP(uint32_t(postTable->italicAngle)));
- deleteTable(postTable);
- }
+static hb_position_t
+_get_glyph_h_advance(hb_font_t*, void *font_data, hb_codepoint_t gid, void*)
+{
+ return _get_glyph_advance((FT_Face) font_data, gid, false);
+}
- return;
+static hb_position_t
+_get_glyph_v_advance(hb_font_t*, void *font_data, hb_codepoint_t gid, void*)
+{
+ return _get_glyph_advance((FT_Face) font_data, gid, true);
+}
-error_exit:
- return;
+static hb_bool_t
+_get_glyph_h_origin(hb_font_t*, void *font_data, hb_codepoint_t gid, hb_position_t *x, hb_position_t *y, void*)
+{
+ return true;
}
-void XeTeXFontInst::setLayoutDirVertical(bool vertical)
+static hb_bool_t
+_get_glyph_v_origin(hb_font_t*, void *font_data, hb_codepoint_t gid, hb_position_t *x, hb_position_t *y, void*)
{
- fVertical = vertical;
- int status = 0;
- initialize(status);
+ FT_Face face = (FT_Face) font_data;
+ FT_Error error;
+
+ error = FT_Load_Glyph (face, gid, ftLoadFlags);
+ if (!error) {
+ *x = face->glyph->metrics.horiBearingX - face->glyph->metrics.vertBearingX;
+ *y = face->glyph->metrics.horiBearingY - (-face->glyph->metrics.vertBearingY);
+ }
+
+ return !error;
}
-void XeTeXFontInst::deleteTable(const void *table) const
+static hb_position_t
+_get_glyph_h_kerning(hb_font_t*, void *font_data, hb_codepoint_t gid1, hb_codepoint_t gid2, void*)
{
- free((void *) table);
+ FT_Face face = (FT_Face) font_data;
+ FT_Error error;
+ FT_Vector kerning;
+ hb_position_t ret;
+
+ error = FT_Get_Kerning (face, gid1, gid2, FT_KERNING_UNFITTED, &kerning);
+ if (error)
+ ret = 0;
+ else
+ ret = kerning.x;
}
-const void *XeTeXFontInst::getFontTable(OTTag tableTag) const
+static hb_position_t
+_get_glyph_v_kerning(hb_font_t*, void *font_data, hb_codepoint_t gid1, hb_codepoint_t gid2, void*)
{
- return FontTableCache::find(tableTag);
+ /* FreeType does not support vertical kerning */
+ return 0;
}
-const void *XeTeXFontInst::getFontTable(OTTag tableTag, uint32_t *length) const
+static hb_bool_t
+_get_glyph_extents(hb_font_t*, void *font_data, hb_codepoint_t gid, hb_glyph_extents_t *extents, void*)
{
- return FontTableCache::find(tableTag, length);
+ FT_Face face = (FT_Face) font_data;
+ FT_Error error;
+
+ error = FT_Load_Glyph (face, gid, ftLoadFlags);
+ if (!error) {
+ extents->x_bearing = face->glyph->metrics.horiBearingX;
+ extents->y_bearing = face->glyph->metrics.horiBearingY;
+ extents->width = face->glyph->metrics.width;
+ extents->height = -face->glyph->metrics.height;
+ }
+
+ return !error;
}
-const void *XeTeXFontInst::readFontTable(OTTag tableTag) const
+static hb_bool_t
+_get_glyph_contour_point(hb_font_t*, void *font_data, hb_codepoint_t gid, unsigned int point_index, hb_position_t *x, hb_position_t *y, void*)
{
- uint32_t len;
+ FT_Face face = (FT_Face) font_data;
+ FT_Error error;
+ bool ret = false;
+
+ error = FT_Load_Glyph (face, gid, ftLoadFlags);
+ if (!error) {
+ if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
+ if (point_index < (unsigned int) face->glyph->outline.n_points) {
+ *x = face->glyph->outline.points[point_index].x;
+ *y = face->glyph->outline.points[point_index].y;
+ ret = true;
+ }
+ }
+ }
- return readTable(tableTag, &len);
+ return ret;
}
-const void *XeTeXFontInst::readFontTable(OTTag tableTag, uint32_t& len) const
+static hb_font_funcs_t *
+_get_font_funcs(void)
{
- return readTable(tableTag, &len);
+ static hb_font_funcs_t* funcs = hb_font_funcs_create();
+
+ hb_font_funcs_set_glyph_func (funcs, _get_glyph, NULL, NULL);
+ hb_font_funcs_set_glyph_h_advance_func (funcs, _get_glyph_h_advance, NULL, NULL);
+ hb_font_funcs_set_glyph_v_advance_func (funcs, _get_glyph_v_advance, NULL, NULL);
+ hb_font_funcs_set_glyph_h_origin_func (funcs, _get_glyph_h_origin, NULL, NULL);
+ hb_font_funcs_set_glyph_v_origin_func (funcs, _get_glyph_v_origin, NULL, NULL);
+ hb_font_funcs_set_glyph_h_kerning_func (funcs, _get_glyph_h_kerning, NULL, NULL);
+ hb_font_funcs_set_glyph_v_kerning_func (funcs, _get_glyph_v_kerning, NULL, NULL);
+ hb_font_funcs_set_glyph_extents_func (funcs, _get_glyph_extents, NULL, NULL);
+ hb_font_funcs_set_glyph_contour_point_func (funcs, _get_glyph_contour_point, NULL, NULL);
+
+ return funcs;
}
-uint16_t XeTeXFontInst::getNumGlyphs() const
+static hb_blob_t *
+_get_table(hb_face_t *, hb_tag_t tag, void *user_data)
{
- if (!fNumGlyphsInited) {
- const MAXPTable *maxpTable = (MAXPTable *) readFontTable(kMAXP);
-
- if (maxpTable != NULL) {
- XeTeXFontInst *realThis = (XeTeXFontInst *) this;
- realThis->fNumGlyphs = SWAP(maxpTable->numGlyphs);
- deleteTable(maxpTable);
- realThis->fNumGlyphsInited = true;
+ FT_Face face = (FT_Face) user_data;
+ FT_ULong length = 0;
+ FT_Byte *table;
+ FT_Error error;
+ hb_blob_t* blob = NULL;
+
+ error = FT_Load_Sfnt_Table(face, tag, 0, NULL, &length);
+ if (!error) {
+ table = (FT_Byte *) xmalloc(length * sizeof(char));
+ if (table != NULL) {
+ error = FT_Load_Sfnt_Table(face, tag, 0, (FT_Byte*)table, &length);
+ if (!error) {
+ blob = hb_blob_create((const char*) table, length, HB_MEMORY_MODE_WRITABLE, table, free);
+ } else {
+ free(table);
+ }
}
- }
+ }
- return fNumGlyphs;
+ return blob;
}
-void XeTeXFontInst::getGlyphAdvance(GlyphID glyph, realpoint &advance) const
+void
+XeTeXFontInst::initialize(const char* pathname, int index, int &status)
{
- if (fMetricsTable == NULL) {
- XeTeXFontInst *realThis = (XeTeXFontInst *) this;
- // we use the fact that 'hmtx' and 'vmtx' have the same format
- realThis->fMetricsTable = (const HMTXTable *) readFontTable(fVertical ? kVMTX : kHMTX);
- }
-
- uint16_t index = glyph;
+ TT_Postscript *postTable;
+ TT_OS2* os2Table;
+ FT_Error error;
+ hb_face_t *hbFace;
+
+ if (!gFreeTypeLibrary) {
+ error = FT_Init_FreeType(&gFreeTypeLibrary);
+ if (error) {
+ fprintf(stderr, "FreeType initialization failed! (%d)\n", error);
+ exit(1);
+ }
+ }
- if (glyph >= getNumGlyphs() || fMetricsTable == NULL) {
- advance.x = advance.y = 0;
+ error = FT_New_Face(gFreeTypeLibrary, (char*)pathname, index, &ftFace);
+ if (error) {
+ status = 1;
return;
}
- if (glyph >= fNumLongMetrics) {
- index = fNumLongMetrics - 1;
- }
+ if (!FT_IS_SCALABLE(ftFace)) {
+ status = 1;
+ return;
+ }
+
+ /* for non-sfnt-packaged fonts (presumably Type 1), see if there is an AFM file we can attach */
+ if (index == 0 && !FT_IS_SFNT(ftFace)) {
+ char* afm = new char[strlen((const char*)pathname) + 5]; // room to append ".afm"
+ strcpy(afm, (const char*)pathname);
+ char* p = strrchr(afm, '.');
+ if (p == NULL || strlen(p) != 4 || tolower(*(p+1)) != 'p' || tolower(*(p+2)) != 'f')
+ strcat(afm, ".afm"); // append .afm if the extension didn't seem to be .pf[ab]
+ else
+ strcpy(p, ".afm"); // else replace extension with .afm
+ FT_Attach_File(ftFace, afm); // ignore error code; AFM might not exist
+ delete[] afm;
+ }
+
+ FT_Set_Char_Size(ftFace, fPointSize * 64, 0, 0, 0);
+
+ char buf[20];
+ if (index > 0)
+ sprintf(buf, ":%d", index);
+ else
+ buf[0] = 0;
+ fFilename = new char[strlen(pathname) + 2 + strlen(buf) + 1];
+ sprintf(fFilename, "[%s%s]", pathname, buf);
+ fUnitsPerEM = ftFace->units_per_EM;
+ fAscent = unitsToPoints(ftFace->ascender);
+ fDescent = unitsToPoints(ftFace->descender);
+
+ postTable = (TT_Postscript *) getFontTable(ft_sfnt_post);
+ if (postTable != NULL) {
+ fItalicAngle = Fix2D(postTable->italicAngle);
+ }
+
+ os2Table = (TT_OS2*) getFontTable(ft_sfnt_os2);
+ if (os2Table) {
+ fCapHeight = unitsToPoints(os2Table->sCapHeight);
+ fXHeight = unitsToPoints(os2Table->sxHeight);
+ }
+
+ hbFace = hb_face_create_for_tables(_get_table, ftFace, NULL);
+ hb_face_set_index(hbFace, index);
+ hb_face_set_upem(hbFace, fUnitsPerEM);
+ hbFont = hb_font_create(hbFace);
+ hb_face_destroy(hbFace);
+
+ hb_font_set_funcs(hbFont, _get_font_funcs(), ftFace, NULL);
+ hb_font_set_scale(hbFont,
+ ((uint64_t) ftFace->size->metrics.x_scale * (uint64_t) fUnitsPerEM) >> 16,
+ ((uint64_t) ftFace->size->metrics.y_scale * (uint64_t) fUnitsPerEM) >> 16);
+ //hb_font_set_ppem(hbFont, ftFace->size->metrics.x_ppem, ftFace->size->metrics.y_ppem);
+
+ return;
+}
- advance.x = unitsToPoints(SWAP(fMetricsTable->hMetrics[index].advanceWidth));
- advance.y = 0;
+void
+XeTeXFontInst::setLayoutDirVertical(bool vertical)
+{
+ fVertical = vertical;
+}
+
+const void *
+XeTeXFontInst::getFontTable(OTTag tag) const
+{
+ FT_ULong tmpLength = 0;
+ FT_Error error = FT_Load_Sfnt_Table(ftFace, tag, 0, NULL, &tmpLength);
+ if (error)
+ return NULL;
+
+ void* table = xmalloc(tmpLength * sizeof(char));
+ if (table != NULL) {
+ error = FT_Load_Sfnt_Table(ftFace, tag, 0, (FT_Byte*)table, &tmpLength);
+ if (error) {
+ free((void *) table);
+ return NULL;
+ }
+ }
+
+ return table;
+}
+
+const char *
+XeTeXFontInst::getMathTable()
+{
+ if (fMath == NULL)
+ fMath = (const char*) getFontTable(MATH_TAG);
+ return fMath;
+}
+
+const void *
+XeTeXFontInst::getFontTable(FT_Sfnt_Tag tag) const
+{
+ return FT_Get_Sfnt_Table(ftFace, tag);
+}
+
+void
+XeTeXFontInst::getGlyphBounds(GlyphID gid, GlyphBBox* bbox)
+{
+ bbox->xMin = bbox->yMin = bbox->xMax = bbox->yMax = 0.0;
+
+ FT_Error error = FT_Load_Glyph(ftFace, gid, FT_LOAD_NO_SCALE);
+ if (error)
+ return;
+
+ FT_Glyph glyph;
+ error = FT_Get_Glyph(ftFace->glyph, &glyph);
+ if (error == 0) {
+ FT_BBox ft_bbox;
+ FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_UNSCALED, &ft_bbox);
+ bbox->xMin = unitsToPoints(ft_bbox.xMin);
+ bbox->yMin = unitsToPoints(ft_bbox.yMin);
+ bbox->xMax = unitsToPoints(ft_bbox.xMax);
+ bbox->yMax = unitsToPoints(ft_bbox.yMax);
+ FT_Done_Glyph(glyph);
+ }
+}
+
+GlyphID
+XeTeXFontInst::mapCharToGlyph(UChar32 ch) const
+{
+ return FT_Get_Char_Index(ftFace, ch);
+}
+
+uint16_t
+XeTeXFontInst::getNumGlyphs() const
+{
+ return ftFace->num_glyphs;
}
float
XeTeXFontInst::getGlyphWidth(GlyphID gid)
{
- realpoint advance;
- getGlyphAdvance(gid, advance);
- return advance.x;
+ return _get_glyph_advance(ftFace, gid, false) / 64.0;
}
void
XeTeXFontInst::getGlyphHeightDepth(GlyphID gid, float* ht, float* dp)
{
- GlyphBBox bbox;
+ GlyphBBox bbox;
getGlyphBounds(gid, &bbox);
-
+
if (ht)
*ht = bbox.yMax;
if (dp)
@@ -220,54 +425,70 @@ XeTeXFontInst::getGlyphHeightDepth(GlyphID gid, float* ht, float* dp)
void
XeTeXFontInst::getGlyphSidebearings(GlyphID gid, float* lsb, float* rsb)
{
- realpoint adv;
- getGlyphAdvance(gid, adv);
+ float width = getGlyphWidth(gid);
- GlyphBBox bbox;
+ GlyphBBox bbox;
getGlyphBounds(gid, &bbox);
if (lsb)
*lsb = bbox.xMin;
if (rsb)
- *rsb = adv.x - bbox.xMax;
+ *rsb = width - bbox.xMax;
}
float
XeTeXFontInst::getGlyphItalCorr(GlyphID gid)
{
- float rval = 0.0;
+ float rval = 0.0;
- realpoint adv;
- getGlyphAdvance(gid, adv);
+ float width = getGlyphWidth(gid);
- GlyphBBox bbox;
+ GlyphBBox bbox;
getGlyphBounds(gid, &bbox);
- if (bbox.xMax > adv.x)
- rval = bbox.xMax - adv.x;
+ if (bbox.xMax > width)
+ rval = bbox.xMax - width;
return rval;
}
GlyphID
XeTeXFontInst::mapGlyphToIndex(const char* glyphName) const
- /* default implementation, may be overridden (e.g. by Freetype-based XeTeXFontInst_ */
{
- uint32_t len;
- const char *p = (const char*)readFontTable(kPOST, len);
- if (p != NULL)
- return findGlyphInPostTable(p, len, glyphName);
- else
- return 0;
+ return FT_Get_Name_Index(ftFace, const_cast<char*>(glyphName));
}
const char*
XeTeXFontInst::getGlyphName(GlyphID gid, int& nameLen)
{
- uint32_t len;
- const char *p = (const char*)readFontTable(kPOST, len);
- if (p != NULL)
- return getGlyphNamePtr(p, len, gid, &nameLen);
- else
+ if (FT_HAS_GLYPH_NAMES(ftFace)) {
+ static char buffer[256];
+ FT_Get_Glyph_Name(ftFace, gid, buffer, 256);
+ nameLen = strlen(buffer);
+ return &buffer[0];
+ }
+ else {
+ nameLen = 0;
return NULL;
+ }
+}
+
+UChar32
+XeTeXFontInst::getFirstCharCode()
+{
+ FT_UInt gindex;
+ return FT_Get_First_Char(ftFace, &gindex);
+}
+
+UChar32
+XeTeXFontInst::getLastCharCode()
+{
+ FT_UInt gindex;
+ UChar32 ch = FT_Get_First_Char(ftFace, &gindex);
+ UChar32 prev = ch;
+ while (gindex != 0) {
+ prev = ch;
+ ch = FT_Get_Next_Char(ftFace, ch, &gindex);
+ }
+ return prev;
}