1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042 |
- /* Copyright (C) 2003 Aladdin Enterprises. 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.
-
- For more information about licensing, please refer to
- http://www.ghostscript.com/licensing/. For information on
- commercial licensing, go to http://www.artifex.com/licensing/ or
- contact Artifex Software, Inc., 101 Lucas Valley Road #110,
- San Rafael, CA 94903, U.S.A., +1(415)492-9861.
- */
- /* $Id: ttfmain.c,v 1.34 2005/08/02 11:12:32 igor Exp $ */
- /* A Free Type interface adapter. */
- /* Uses code fragments from the FreeType project. */
- #include "ttmisc.h"
- #include "ttfoutl.h"
- #include "ttfmemd.h"
- #include "ttfinp.h"
- #include "ttfsfnt.h"
- #include "ttobjs.h"
- #include "ttinterp.h"
- #include "ttcalc.h"
- private const bool skip_instructions = 0; /* Debug purpose only. */
- typedef struct {
- Fixed a, b, c, d, tx, ty;
- } FixMatrix;
- struct ttfSubGlyphUsage_s {
- FixMatrix m;
- int index;
- int flags;
- short arg1, arg2;
- };
- /*------------------------------------------------------------------- */
- private Fixed AVE(F26Dot6 a, F26Dot6 b)
- { return (a + b) / 2;
- }
- private F26Dot6 shortToF26Dot6(short a)
- { return (F26Dot6)a << 6;
- }
- private F26Dot6 floatToF26Dot6(float a)
- { return (F26Dot6)(a * (1 << 6) + 0.5);
- }
- private Fixed floatToF16Dot16(float a)
- { return (F26Dot6)(a * (1 << 16) + 0.5);
- }
- private void TransformF26Dot6PointFix(F26Dot6Point *pt, F26Dot6 dx, F26Dot6 dy, FixMatrix *m)
- { pt->x = MulDiv(dx, m->a, 65536) + MulDiv(dy, m->c, 65536) + (m->tx >> 10);
- pt->y = MulDiv(dx, m->b, 65536) + MulDiv(dy, m->d, 65536) + (m->ty >> 10);
- }
- private void TransformF26Dot6PointFloat(FloatPoint *pt, F26Dot6 dx, F26Dot6 dy, FloatMatrix *m)
- { pt->x = dx * m->a / 64 + dy * m->c / 64 + m->tx;
- pt->y = dx * m->b / 64 + dy * m->d / 64 + m->ty;
- }
- /*-------------------------------------------------------------------*/
- private ttfPtrElem *ttfFont__get_table_ptr(ttfFont *f, char *id)
- {
- if (!memcmp(id, "cvt ", 4))
- return &f->t_cvt_;
- if (!memcmp(id, "fpgm", 4))
- return &f->t_fpgm;
- if (!memcmp(id, "glyf", 4))
- return &f->t_glyf;
- if (!memcmp(id, "head", 4))
- return &f->t_head;
- if (!memcmp(id, "hhea", 4))
- return &f->t_hhea;
- if (!memcmp(id, "hmtx", 4))
- return &f->t_hmtx;
- if (!memcmp(id, "vhea", 4))
- return &f->t_vhea;
- if (!memcmp(id, "vmtx", 4))
- return &f->t_vmtx;
- if (!memcmp(id, "loca", 4))
- return &f->t_loca;
- if (!memcmp(id, "maxp", 4))
- return &f->t_maxp;
- if (!memcmp(id, "prep", 4))
- return &f->t_prep;
- if (!memcmp(id, "cmap", 4))
- return &f->t_cmap;
- return 0;
- }
- /*-------------------------------------------------------------------*/
- TT_Error TT_Set_Instance_CharSizes(TT_Instance instance,
- TT_F26Dot6 charWidth,
- TT_F26Dot6 charHeight)
- {
- PInstance ins = instance.z;
- if ( !ins )
- return TT_Err_Invalid_Instance_Handle;
- if (charWidth < 1*64)
- charWidth = 1*64;
- if (charHeight < 1*64)
- charHeight = 1*64;
- ins->metrics.x_scale1 = charWidth;
- ins->metrics.y_scale1 = charHeight;
- ins->metrics.x_scale2 = ins->face->font->nUnitsPerEm;
- ins->metrics.y_scale2 = ins->face->font->nUnitsPerEm;
- if (ins->face->font->nFlags & 8) {
- ins->metrics.x_scale1 = (ins->metrics.x_scale1+32) & -64;
- ins->metrics.y_scale1 = (ins->metrics.y_scale1+32) & -64;
- }
- ins->metrics.x_ppem = ins->metrics.x_scale1 / 64;
- ins->metrics.y_ppem = ins->metrics.y_scale1 / 64;
- if (charWidth > charHeight)
- ins->metrics.pointSize = charWidth;
- else
- ins->metrics.pointSize = charHeight;
- ins->valid = FALSE;
- return Instance_Reset(ins, FALSE);
- }
- /*-------------------------------------------------------------------*/
- int ttfInterpreter__obtain(ttfMemory *mem, ttfInterpreter **ptti)
- {
- ttfInterpreter *tti;
- if (*ptti) {
- (*ptti)->lock++;
- return 0;
- }
- tti = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_ttfInterpreter, "ttfInterpreter__obtain");
- if (!tti)
- return fMemoryError;
- tti->usage = 0;
- tti->usage_size = 0;
- tti->ttf_memory = mem;
- tti->lock = 1;
- tti->exec = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_TExecution_Context, "ttfInterpreter__obtain");
- if (!tti->exec) {
- mem->free(mem, tti, "ttfInterpreter__obtain");
- return fMemoryError;
- }
- memset(tti->exec, 0, sizeof(*tti->exec));
- *ptti = tti;
- return 0;
- }
- void ttfInterpreter__release(ttfInterpreter **ptti)
- {
- ttfInterpreter *tti = *ptti;
- ttfMemory *mem = tti->ttf_memory;
- if(--tti->lock)
- return;
- mem->free(mem, tti->usage, "ttfInterpreter__release");
- mem->free(mem, tti->exec, "ttfInterpreter__release");
- mem->free(mem, *ptti, "ttfInterpreter__release");
- mem->free(mem, mem, "ttfInterpreter__release");
- *ptti = 0;
- }
- /*-------------------------------------------------------------------*/
- void ttfFont__init(ttfFont *this, ttfMemory *mem,
- void (*DebugRepaint)(ttfFont *),
- int (*DebugPrint)(ttfFont *, const char *s, ...))
- {
- memset(this, 0, sizeof(*this));
- this->DebugRepaint = DebugRepaint;
- this->DebugPrint = DebugPrint;
- }
- void ttfFont__finit(ttfFont *this)
- { ttfMemory *mem = this->tti->ttf_memory;
- if (this->exec)
- Context_Destroy(this->exec);
- this->exec = NULL;
- if (this->inst)
- Instance_Destroy(this->inst);
- mem->free(mem, this->inst, "ttfFont__finit");
- this->inst = NULL;
- if (this->face)
- Face_Destroy(this->face);
- mem->free(mem, this->face, "ttfFont__finit");
- this->face = NULL;
- }
- #define MAX_SUBGLYPH_NESTING 3 /* Arbitrary. We need this because we don't want
- a ttfOutliner__BuildGlyphOutline recursion
- while a glyph is loaded in ttfReader. */
- FontError ttfFont__Open(ttfInterpreter *tti, ttfFont *this, ttfReader *r,
- unsigned int nTTC, float w, float h,
- bool design_grid)
- { char sVersion[4], sVersion0[4] = {0, 1, 0, 0};
- unsigned int nNumTables, i;
- TT_Error code;
- int k;
- TT_Instance I;
- ttfMemory *mem = tti->ttf_memory;
- F26Dot6 ww, hh;
- this->tti = tti;
- this->design_grid = design_grid;
- r->Read(r, sVersion, 4);
- if(!memcmp(sVersion, "ttcf", 4)) {
- unsigned int nFonts;
- unsigned int nPos = 0xbaadf00d; /* Quiet compiler. */
- r->Read(r, sVersion, 4);
- if(memcmp(sVersion, sVersion0, 4))
- return fUnimplemented;
- nFonts = ttfReader__UInt(r);
- if (nFonts == 0)
- return fBadFontData;
- if(nTTC >= nFonts)
- return fTableNotFound;
- for(i = 0; i <= nTTC; i++)
- nPos = ttfReader__UInt(r);
- r->Seek(r, nPos);
- r->Read(r, sVersion, 4);
- }
- if(memcmp(sVersion, sVersion0, 4) && memcmp(sVersion, "true", 4))
- return fUnimplemented;
- nNumTables = ttfReader__UShort(r);
- ttfReader__UShort(r); /* nSearchRange */
- ttfReader__UShort(r); /* nEntrySelector */
- ttfReader__UShort(r); /* nRangeShift */
- for (i = 0; i < nNumTables; i++) {
- char sTag[5];
- unsigned int nOffset, nLength;
- ttfPtrElem *e;
- sTag[4] = 0;
- r->Read(r, sTag, 4);
- ttfReader__UInt(r); /* nCheckSum */
- nOffset = ttfReader__UInt(r);
- nLength = ttfReader__UInt(r);
- e = ttfFont__get_table_ptr(this, sTag);
- if (e != NULL) {
- e->nPos = nOffset;
- e->nLen = nLength;
- }
- }
- r->Seek(r, this->t_head.nPos + offset_of(sfnt_FontHeader, flags));
- this->nFlags = ttfReader__UShort(r);
- r->Seek(r, this->t_head.nPos + offset_of(sfnt_FontHeader, unitsPerEm));
- this->nUnitsPerEm = ttfReader__UShort(r);
- r->Seek(r, this->t_head.nPos + offset_of(sfnt_FontHeader, indexToLocFormat));
- this->nIndexToLocFormat = ttfReader__UShort(r);
- r->Seek(r, this->t_maxp.nPos + offset_of(sfnt_maxProfileTable, numGlyphs));
- this->nNumGlyphs = ttfReader__UShort(r);
- r->Seek(r, this->t_maxp.nPos + offset_of(sfnt_maxProfileTable, maxComponentElements));
- this->nMaxComponents = ttfReader__UShort(r);
- if(this->nMaxComponents < 10)
- this->nMaxComponents = 10; /* work around DynaLab bug in lgoth.ttf */
- r->Seek(r, this->t_hhea.nPos + offset_of(sfnt_MetricsHeader, numberLongMetrics));
- this->nLongMetricsHorz = ttfReader__UShort(r);
- if (this->t_vhea.nPos != 0) {
- r->Seek(r, this->t_vhea.nPos + offset_of(sfnt_MetricsHeader, numberLongMetrics));
- this->nLongMetricsVert = ttfReader__UShort(r);
- } else
- this->nLongMetricsVert = 0;
- if (tti->usage_size < this->nMaxComponents * MAX_SUBGLYPH_NESTING) {
- tti->ttf_memory->free(tti->ttf_memory, tti->usage, "ttfFont__Open");
- tti->usage_size = 0;
- tti->usage = mem->alloc_bytes(mem,
- sizeof(ttfSubGlyphUsage) * this->nMaxComponents * MAX_SUBGLYPH_NESTING,
- "ttfFont__Open");
- if (tti->usage == NULL)
- return fMemoryError;
- tti->usage_size = this->nMaxComponents * MAX_SUBGLYPH_NESTING;
- }
- this->face = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_TFace, "ttfFont__Open");
- if (this->face == NULL)
- return fMemoryError;
- memset(this->face, 0, sizeof(*this->face));
- this->face->r = r;
- this->face->font = this;
- this->exec = tti->exec;
- code = Face_Create(this->face);
- if (code)
- return fMemoryError;
- code = r->Error(r);
- if (code < 0)
- return fBadFontData;
- this->inst = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_TInstance, "ttfFont__Open");
- if (this->inst == NULL)
- return fMemoryError;
- memset(this->inst, 0, sizeof(*this->inst));
- code = Context_Create(this->exec, this->face); /* See comment in the implementation of Context_Create. */
- if (code == TT_Err_Out_Of_Memory)
- return fMemoryError;
- code = Instance_Create(this->inst, this->face);
- if (code == TT_Err_Out_Of_Memory)
- return fMemoryError;
- if (code)
- return fBadFontData;
- for(k = 0; k < this->face->cvtSize; k++)
- this->inst->cvt[k] = shortToF26Dot6(this->face->cvt[k]);
- code = Instance_Init(this->inst);
- if (code == TT_Err_Out_Of_Memory)
- return fMemoryError;
- if (code >= TT_Err_Invalid_Opcode && code <= TT_Err_Invalid_Displacement)
- return fBadInstruction;
- if (code)
- return fBadFontData;
- I.z = this->inst;
- if (design_grid)
- ww = hh = shortToF26Dot6(this->nUnitsPerEm);
- else {
- /* Round towards zero for a better view of mirrored characters : */
- ww = floatToF26Dot6(w);
- hh = floatToF26Dot6(h);
- }
- code = TT_Set_Instance_CharSizes(I, ww, hh);
- this->inst->metrics = this->exec->metrics;
- if (code == TT_Err_Invalid_Engine)
- return fPatented;
- if (code == TT_Err_Out_Of_Memory)
- return fMemoryError;
- if (code >= TT_Err_Invalid_Opcode && code <= TT_Err_Invalid_Displacement)
- return fBadInstruction;
- if (code)
- return fBadFontData;
- return code;
- }
- private void ttfFont__StartGlyph(ttfFont *this)
- { Context_Load( this->exec, this->inst );
- if ( this->inst->GS.instruct_control & 2 )
- this->exec->GS = Default_GraphicsState;
- else
- this->exec->GS = this->inst->GS;
- this->tti->usage_top = 0;
- }
- private void ttfFont__StopGlyph(ttfFont *this)
- {
- Context_Save(this->exec, this->inst);
- }
- /*-------------------------------------------------------------------*/
- private void mount_zone( PGlyph_Zone source,
- PGlyph_Zone target )
- {
- Int np, nc;
- np = source->n_points;
- nc = source->n_contours;
- target->org_x = source->org_x + np;
- target->org_y = source->org_y + np;
- target->cur_x = source->cur_x + np;
- target->cur_y = source->cur_y + np;
- target->touch = source->touch + np;
- target->contours = source->contours + nc;
- target->n_points = 0;
- target->n_contours = 0;
- }
- private void Init_Glyph_Component( PSubglyph_Record element,
- PSubglyph_Record original,
- PExecution_Context exec )
- {
- element->index = -1;
- element->is_scaled = FALSE;
- element->is_hinted = FALSE;
- if (original)
- mount_zone( &original->zone, &element->zone );
- else
- element->zone = exec->pts;
- element->zone.n_contours = 0;
- element->zone.n_points = 0;
- element->arg1 = 0;
- element->arg2 = 0;
- element->element_flag = 0;
- element->preserve_pps = FALSE;
- element->transform.xx = 1 << 16;
- element->transform.xy = 0;
- element->transform.yx = 0;
- element->transform.yy = 1 << 16;
- element->transform.ox = 0;
- element->transform.oy = 0;
- element->leftBearing = 0;
- element->advanceWidth = 0;
- }
- private void cur_to_org( Int n, PGlyph_Zone zone )
- {
- Int k;
- for ( k = 0; k < n; k++ )
- zone->org_x[k] = zone->cur_x[k];
- for ( k = 0; k < n; k++ )
- zone->org_y[k] = zone->cur_y[k];
- }
- private void org_to_cur( Int n, PGlyph_Zone zone )
- {
- Int k;
- for ( k = 0; k < n; k++ )
- zone->cur_x[k] = zone->org_x[k];
- for ( k = 0; k < n; k++ )
- zone->cur_y[k] = zone->org_y[k];
- }
- /*-------------------------------------------------------------------*/
- void ttfOutliner__init(ttfOutliner *this, ttfFont *f, ttfReader *r, ttfExport *exp,
- bool bOutline, bool bFirst, bool bVertical)
- {
- this->r = r;
- this->bOutline = bOutline;
- this->bFirst = bFirst;
- this->pFont = f;
- this->bVertical = bVertical;
- this->exp = exp;
- }
- private void MoveGlyphOutline(TGlyph_Zone *pts, int nOffset, ttfGlyphOutline *out, FixMatrix *m)
- { F26Dot6* x = pts->org_x + nOffset;
- F26Dot6* y = pts->org_y + nOffset;
- short count = out->pointCount;
- F26Dot6Point p;
- if (m->a == 65536 && m->b == 0 &&
- m->c == 0 && m->d == 65536 &&
- m->tx == 0 && m->ty == 0)
- return;
- for (; count != 0; --count) {
- TransformF26Dot6PointFix(&p, *x, *y, m);
- *x++ = p.x;
- *y++ = p.y;
- }
- }
- private FontError ttfOutliner__BuildGlyphOutlineAux(ttfOutliner *this, int glyphIndex,
- FixMatrix *m_orig, ttfGlyphOutline* gOutline)
- { ttfFont *pFont = this->pFont;
- ttfReader *r = this->r;
- ttfInterpreter *tti = pFont->tti;
- short sideBearing;
- FontError error = fNoError;
- short arg1, arg2;
- short count;
- unsigned int nMtxPos, nMtxGlyph = glyphIndex, nLongMetrics, i;
- unsigned short nAdvance;
- unsigned int nNextGlyphPtr = 0;
- unsigned int nPosBeg;
- TExecution_Context *exec = pFont->exec;
- TGlyph_Zone *pts = &exec->pts;
- TSubglyph_Record subglyph;
- ttfSubGlyphUsage *usage = tti->usage + tti->usage_top;
- const byte *glyph = NULL;
- int glyph_size;
- if(this->bVertical && pFont->t_vhea.nPos && pFont->t_vmtx.nPos) {
- nLongMetrics = pFont->nLongMetricsVert;
- nMtxPos = pFont->t_vmtx.nPos;
- } else {
- nLongMetrics = pFont->nLongMetricsHorz;
- nMtxPos = pFont->t_hmtx.nPos;
- }
- if (this->bVertical && (!pFont->t_vhea.nPos || pFont->t_vmtx.nPos) && nMtxGlyph < nLongMetrics) {
- /* A bad font fix. */
- nMtxGlyph = nLongMetrics;
- if(nMtxGlyph >= pFont->nNumGlyphs)
- nMtxGlyph = pFont->nNumGlyphs - 1;
- }
- if (nMtxGlyph < nLongMetrics) {
- r->Seek(r, nMtxPos + 4 * nMtxGlyph);
- nAdvance = ttfReader__Short(r);
- sideBearing = ttfReader__Short(r);
- } else {
- r->Seek(r, nMtxPos + 4 * (nLongMetrics - 1));
- nAdvance = ttfReader__Short(r);
- r->Seek(r, nMtxPos + 4 * nLongMetrics + 2 * (nMtxGlyph - nLongMetrics));
- sideBearing = ttfReader__Short(r);
- }
- if (r->Error(r))
- goto errex;
- gOutline->sideBearing = shortToF26Dot6(sideBearing);
- gOutline->advance.x = shortToF26Dot6(nAdvance);
- gOutline->advance.y = 0;
- this->bFirst = FALSE;
- if (!this->bOutline)
- return fNoError;
- if (!r->LoadGlyph(r, glyphIndex, &glyph, &glyph_size))
- return fGlyphNotFound;
- if (r->Eof(r)) {
- r->ReleaseGlyph(r, glyphIndex);
- gOutline->xMinB = gOutline->yMinB = 0;
- gOutline->xMaxB = gOutline->yMaxB = 0;
- return fNoError;
- }
- if (r->Error(r))
- goto errex;
- nPosBeg = r->Tell(r);
- gOutline->contourCount = ttfReader__Short(r);
- subglyph.bbox.xMin = ttfReader__Short(r);
- subglyph.bbox.yMin = ttfReader__Short(r);
- subglyph.bbox.xMax = ttfReader__Short(r);
- subglyph.bbox.yMax = ttfReader__Short(r);
- gOutline->xMinB = subglyph.bbox.xMin;
- gOutline->yMinB = subglyph.bbox.yMin;
- gOutline->xMaxB = subglyph.bbox.xMax;
- gOutline->yMaxB = subglyph.bbox.yMax;
- /* FreeType stuff beg */
- Init_Glyph_Component(&subglyph, NULL, pFont->exec);
- subglyph.leftBearing = sideBearing;
- subglyph.advanceWidth = nAdvance;
- subglyph.pp1.x = subglyph.bbox.xMin - sideBearing;
- subglyph.pp1.y = 0;
- subglyph.pp2.x = subglyph.pp1.x + nAdvance;
- subglyph.pp2.y = 0;
- /* FreeType stuff end */
- if (gOutline->contourCount == 0)
- gOutline->pointCount = 0;
- else if (gOutline->contourCount == -1) {
- unsigned short flags, index, bHaveInstructions = 0;
- unsigned int nUsage = 0;
- unsigned int nPos;
- unsigned int n_ins;
- gOutline->bCompound = TRUE;
- if (tti->usage_top + pFont->nMaxComponents > tti->usage_size)
- return fBadFontData;
- gOutline->contourCount = gOutline->pointCount = 0;
- do {
- FixMatrix m;
- ttfSubGlyphUsage *e;
- if (nUsage >= pFont->nMaxComponents) {
- error = fMemoryError; goto ex;
- }
- flags = ttfReader__UShort(r);
- index = ttfReader__UShort(r);
- bHaveInstructions |= (flags & WE_HAVE_INSTRUCTIONS);
- if (flags & ARG_1_AND_2_ARE_WORDS) {
- arg1 = ttfReader__Short(r);
- arg2 = ttfReader__Short(r);
- } else {
- if (flags & ARGS_ARE_XY_VALUES) {
- /* offsets are signed */
- arg1 = ttfReader__SignedByte(r);
- arg2 = ttfReader__SignedByte(r);
- } else { /* anchor points are unsigned */
- arg1 = ttfReader__Byte(r);
- arg2 = ttfReader__Byte(r);
- }
- }
- m.b = m.c = m.tx = m.ty = 0;
- if (flags & WE_HAVE_A_SCALE)
- m.a = m.d = (Fixed)ttfReader__Short(r) << 2;
- else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
- m.a = (Fixed)ttfReader__Short(r) << 2;
- m.d = (Fixed)ttfReader__Short(r) << 2;
- } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
- m.a = (Fixed)ttfReader__Short(r)<<2;
- m.b = (Fixed)ttfReader__Short(r)<<2;
- m.c = (Fixed)ttfReader__Short(r)<<2;
- m.d = (Fixed)ttfReader__Short(r)<<2;
- } else
- m.a = m.d = 65536;
- e = &usage[nUsage];
- e->m = m;
- e->index = index;
- e->arg1 = arg1;
- e->arg2 = arg2;
- e->flags = flags;
- nUsage++;
- } while (flags & MORE_COMPONENTS);
- /* Some fonts have bad WE_HAVE_INSTRUCTIONS, so use nNextGlyphPtr : */
- if (r->Error(r))
- goto errex;
- nPos = r->Tell(r);
- n_ins = ((!r->Eof(r) && (bHaveInstructions || nPos < nNextGlyphPtr)) ? ttfReader__UShort(r) : 0);
- nPos = r->Tell(r);
- r->ReleaseGlyph(r, glyphIndex);
- glyph = NULL;
- for (i = 0; i < nUsage; i++) {
- ttfGlyphOutline out;
- ttfSubGlyphUsage *e = &usage[i];
- int j;
- TT_Error code;
- int nPointsStored = this->nPointsTotal, nContoursStored = this->nContoursTotal;
- out.contourCount = 0;
- out.pointCount = 0;
- out.bCompound = FALSE;
- pts->org_x += nPointsStored;
- pts->org_y += nPointsStored;
- pts->cur_x += nPointsStored;
- pts->cur_y += nPointsStored;
- pts->touch += nPointsStored;
- pts->contours += nContoursStored;
- tti->usage_top += nUsage;
- code = ttfOutliner__BuildGlyphOutlineAux(this, e->index, m_orig, &out);
- pts->org_x -= nPointsStored;
- pts->org_y -= nPointsStored;
- pts->cur_x -= nPointsStored;
- pts->cur_y -= nPointsStored;
- pts->touch -= nPointsStored;
- tti->usage_top -= nUsage;
- pts->contours -= nContoursStored;
- if (code == fPatented)
- error = code;
- else if (code != fNoError) {
- error = code;
- goto ex;
- }
- if (flags & ARGS_ARE_XY_VALUES) {
- e->m.tx = Scale_X( &exec->metrics, e->arg1 ) << 10;
- e->m.ty = Scale_Y( &exec->metrics, e->arg2 ) << 10;
- } else {
- e->m.tx = (pts->org_x[e->arg1] - pts->org_x[gOutline->pointCount + e->arg2]) << 10;
- e->m.ty = (pts->org_y[e->arg1] - pts->org_y[gOutline->pointCount + e->arg2]) << 10;
- }
- MoveGlyphOutline(pts, nPointsStored, &out, &e->m);
- for (j = nContoursStored; j < out.contourCount + nContoursStored; j++)
- pts->contours[j] += nPointsStored;
- gOutline->contourCount += out.contourCount;
- gOutline->pointCount += out.pointCount;
- if(e->flags & USE_MY_METRICS) {
- gOutline->advance.x = out.advance.x;
- gOutline->sideBearing = out.sideBearing;
- }
- }
- if (!skip_instructions && n_ins &&
- !(pFont->inst->GS.instruct_control & 1)) {
- TT_Error code;
- r->LoadGlyph(r, glyphIndex, &glyph, &glyph_size);
- if (r->Error(r))
- goto errex;
- if (nPos + n_ins > glyph_size)
- goto errex;
- code = Set_CodeRange(exec, TT_CodeRange_Glyph, (byte *)glyph + nPos, n_ins);
- if (!code) {
- int nPoints = gOutline->pointCount + 2;
- int k;
- F26Dot6 x;
- exec->pts = subglyph.zone;
- pts->n_points = nPoints;
- pts->n_contours = gOutline->contourCount;
- /* add phantom points : */
- pts->org_x[nPoints - 2] = Scale_X(&exec->metrics, subglyph.pp1.x);
- pts->org_y[nPoints - 2] = Scale_Y(&exec->metrics, subglyph.pp1.y);
- pts->org_x[nPoints - 1] = Scale_X(&exec->metrics, subglyph.pp2.x);
- pts->org_y[nPoints - 1] = Scale_Y(&exec->metrics, subglyph.pp2.y);
- pts->touch[nPoints - 1] = 0;
- pts->touch[nPoints - 2] = 0;
- /* if hinting, round the phantom points (not sure) : */
- x = pts->org_x[nPoints - 2];
- x = ((x + 32) & -64) - x;
- if (x)
- for (k = 0; k < nPoints; k++)
- pts->org_x[k] += x;
- pts->cur_x[nPoints - 1] = (pts->cur_x[nPoints - 1] + 32) & -64;
- for (k = 0; k < nPoints; k++)
- pts->touch[k] = pts->touch[k] & TT_Flag_On_Curve;
- org_to_cur(nPoints, pts);
- exec->is_composite = TRUE;
- if (pFont->patented)
- code = TT_Err_Invalid_Engine;
- else
- code = Context_Run(exec, FALSE);
- if (!code)
- cur_to_org(nPoints, pts);
- else if (code == TT_Err_Invalid_Engine)
- error = fPatented;
- else
- error = fBadFontData;
- }
- Unset_CodeRange(exec);
- Clear_CodeRange(exec, TT_CodeRange_Glyph);
- }
- } else if (gOutline->contourCount > 0) {
- uint16 i;
- int nPoints;
- bool bInsOK;
- byte *onCurve, *stop, flag;
- short *endPoints;
- unsigned int nPos;
- unsigned int n_ins;
- if (this->nContoursTotal + gOutline->contourCount > exec->n_contours) {
- error = fBadFontData; goto ex;
- }
- endPoints = pts->contours;
- for (i = 0; i < gOutline->contourCount; i++)
- endPoints[i] = ttfReader__Short(r);
- for (i = 1; i < gOutline->contourCount; i++)
- if (endPoints[i - 1] >= endPoints[i]) {
- error = fBadFontData; goto ex;
- }
- nPoints = gOutline->pointCount = endPoints[gOutline->contourCount - 1] + 1;
- if (this->nPointsTotal + nPoints + 2 > exec->n_points) {
- error = fBadFontData; goto ex;
- }
- n_ins = ttfReader__Short(r);
- nPos = r->Tell(r);
- r->Seek(r, nPos + n_ins);
- if (r->Error(r))
- goto errex;
- bInsOK = !Set_CodeRange(exec, TT_CodeRange_Glyph, (byte *)glyph + nPos, n_ins);
- onCurve = pts->touch;
- stop = onCurve + gOutline->pointCount;
- while (onCurve < stop) {
- *onCurve++ = flag = ttfReader__Byte(r);
- if (flag & REPEAT_FLAGS) {
- count = ttfReader__Byte(r);
- for (--count; count >= 0; --count)
- *onCurve++ = flag;
- }
- }
- /* Lets do X */
- { short coord = (this->bVertical ? 0 : sideBearing - subglyph.bbox.xMin);
- F26Dot6* x = pts->org_x;
- onCurve = pts->touch;
- while (onCurve < stop) {
- if ((flag = *onCurve++) & XSHORT) {
- if (flag & SHORT_X_IS_POS)
- coord += ttfReader__Byte(r);
- else
- coord -= ttfReader__Byte(r);
- } else if (!(flag & NEXT_X_IS_ZERO))
- coord += ttfReader__Short(r);
- *x++ = Scale_X(&exec->metrics, coord);
- }
- }
- /* Lets do Y */
- { short coord = 0;
- F26Dot6* y = pts->org_y;
- onCurve = pts->touch;
- while (onCurve < stop) {
- if((flag = *onCurve) & YSHORT)
- if ( flag & SHORT_Y_IS_POS )
- coord += ttfReader__Byte(r);
- else
- coord -= ttfReader__Byte(r);
- else if(!(flag & NEXT_Y_IS_ZERO))
- coord += ttfReader__Short(r);
- *y++ = Scale_Y( &exec->metrics, coord );
-
- /* Filter off the extra bits */
- *onCurve++ = flag & ONCURVE;
- }
- }
- MoveGlyphOutline(pts, 0, gOutline, m_orig);
- this->nContoursTotal += gOutline->contourCount;
- this->nPointsTotal += nPoints;
- if (!skip_instructions &&
- !r->Error(r) && n_ins && bInsOK && !(pFont->inst->GS.instruct_control & 1)) {
- TGlyph_Zone *pts = &exec->pts;
- int k;
- F26Dot6 x;
- TT_Error code;
- exec->is_composite = FALSE;
- /* add phantom points : */
- pts->org_x[nPoints ] = Scale_X(&exec->metrics, subglyph.pp1.x);
- pts->org_y[nPoints ] = Scale_Y(&exec->metrics, subglyph.pp1.y);
- pts->org_x[nPoints + 1] = Scale_X(&exec->metrics, subglyph.pp2.x);
- pts->org_y[nPoints + 1] = Scale_Y(&exec->metrics, subglyph.pp2.y);
- pts->touch[nPoints ] = 0;
- pts->touch[nPoints + 1] = 0;
- pts->n_points = nPoints + 2;
- pts->n_contours = gOutline->contourCount;
- /* if hinting, round the phantom points (not sure) : */
- x = pts->org_x[nPoints];
- x = ((x + 32) & -64) - x;
- if (x)
- for (k = 0; k < nPoints + 2; k++)
- pts->org_x[k] += x;
- pts->cur_x[nPoints + 1] = (pts->cur_x[nPoints + 1] + 32) & -64;
- org_to_cur(nPoints + 2, pts);
- exec->is_composite = FALSE;
- for (k = 0; k < nPoints + 2; k++)
- pts->touch[k] &= TT_Flag_On_Curve;
- if (pFont->patented)
- code = TT_Err_Invalid_Engine;
- else
- code = Context_Run(exec, FALSE );
- if (!code)
- cur_to_org(nPoints + 2, pts);
- else if (code == TT_Err_Invalid_Engine)
- error = fPatented;
- else
- error = fBadInstruction;
- gOutline->sideBearing = subglyph.bbox.xMin - subglyph.pp1.x;
- gOutline->advance.x = subglyph.pp2.x - subglyph.pp1.x;
- }
- Unset_CodeRange(exec);
- Clear_CodeRange(exec, TT_CodeRange_Glyph);
- } else
- error = fBadFontData;
- goto ex;
- errex:;
- error = fBadFontData;
- ex:;
- r->ReleaseGlyph(r, glyphIndex);
- return error;
- }
- private FontError ttfOutliner__BuildGlyphOutline(ttfOutliner *this, int glyphIndex,
- float orig_x, float orig_y, ttfGlyphOutline* gOutline)
- {
- FixMatrix m_orig = {1 << 16, 0, 0, 1 << 16, 0, 0};
- /* Round towards zero like old character coordinate conversions do. */
- m_orig.tx = floatToF16Dot16(orig_x);
- m_orig.ty = floatToF16Dot16(orig_y);
- return ttfOutliner__BuildGlyphOutlineAux(this, glyphIndex, &m_orig, gOutline);
- }
- #define AVECTOR_BUG 1 /* Work around a bug in AVector fonts. */
- void ttfOutliner__DrawGlyphOutline(ttfOutliner *this)
- { ttfGlyphOutline* out = &this->out;
- FloatMatrix *m = &this->post_transform;
- ttfFont *pFont = this->pFont;
- ttfExport *exp = this->exp;
- TExecution_Context *exec = pFont->exec;
- TGlyph_Zone *pts = &exec->pts;
- short* endP = pts->contours;
- byte* onCurve = pts->touch;
- F26Dot6* x = pts->org_x;
- F26Dot6* y = pts->org_y;
- F26Dot6 px, py;
- short sp, ctr;
- FloatPoint p0, p1, p2, p3;
- # if AVECTOR_BUG
- short xMinB = out->xMinB >> 6, xMaxB=out->xMaxB >> 6;
- short yMinB = out->yMinB >> 6, yMaxB=out->yMaxB >> 6;
- short expand=pFont->nUnitsPerEm*2;
- F26Dot6 xMin, xMax, yMin, yMax;
- xMinB -= expand;
- yMinB -= expand;
- xMaxB += expand;
- yMaxB += expand;
- xMin = Scale_X(&exec->metrics, xMinB);
- xMax = Scale_X(&exec->metrics, xMaxB);
- yMin = Scale_X(&exec->metrics, yMinB);
- yMax = Scale_X(&exec->metrics, yMaxB);
- # endif
- TransformF26Dot6PointFloat(&p1, out->advance.x, out->advance.y, m);
- p1.x -= this->post_transform.tx;
- p1.y -= this->post_transform.ty;
- exp->SetWidth(exp, &p1);
- sp = -1;
- for (ctr = out->contourCount; ctr != 0; --ctr) {
- short pt, pts = *endP - sp;
- short ep = pts - 1;
- if (pts < 3) {
- x += pts;
- y += pts;
- onCurve += pts;
- sp = *endP++;
- continue; /* skip 1 and 2 point contours */
- }
- if (exp->bPoints) {
- for (pt = 0; pt <= ep; pt++) {
- px = x[pt], py = y[pt];
- # if AVECTOR_BUG
- if (x[pt] < xMin || xMax < x[pt] || y[pt] < yMin || yMax < y[pt]) {
- short prevIndex = pt == 0 ? ep : pt - 1;
- short nextIndex = pt == ep ? 0 : pt + 1;
- if (nextIndex > ep)
- nextIndex = 0;
- px=AVE(x[prevIndex], x[nextIndex]);
- py=AVE(y[prevIndex], y[nextIndex]);
- }
- # endif
- TransformF26Dot6PointFloat(&p0, px, py, m);
- exp->Point(exp, &p0, onCurve[pt], !pt);
- }
- }
- if (exp->bOutline) {
- pt = 0;
- if(onCurve[ep] & 1) {
- px = x[ep];
- py = y[ep];
- } else if (onCurve[0] & 1) {
- px = x[0];
- py = y[0];
- pt = 1;
- } else {
- px = AVE(x[0], x[ep]);
- py = AVE(y[0], y[ep]);
- }
- this->ppx = px; this->ppy = py;
- TransformF26Dot6PointFloat(&p0, px, py, m);
- exp->MoveTo(exp, &p0);
- for (; pt <= ep; pt++) {
- short prevIndex = pt == 0 ? ep : pt - 1;
- short nextIndex = pt == ep ? 0 : pt + 1;
- if (onCurve[pt] & 1) {
- if (onCurve[prevIndex] & 1) {
- px = x[pt];
- py = y[pt];
- if (this->ppx != px || this->ppy != py) {
- TransformF26Dot6PointFloat(&p1, px, py, m);
- exp->LineTo(exp, &p1);
- this->ppx = px; this->ppy = py;
- p0 = p1;
- }
- }
- } else {
- F26Dot6 prevX, prevY, nextX, nextY;
- px = x[pt];
- py = y[pt];
- # if AVECTOR_BUG
- if(x[pt] < xMin || xMax < x[pt] || y[pt] < yMin || yMax < y[pt]) {
- px=AVE(x[prevIndex], x[nextIndex]);
- py=AVE(y[prevIndex], y[nextIndex]);
- }
- # endif
- if (onCurve[prevIndex] & 1) {
- prevX = x[prevIndex];
- prevY = y[prevIndex];
- } else {
- prevX = AVE(x[prevIndex], px);
- prevY = AVE(y[prevIndex], py);
- }
- if (onCurve[nextIndex] & 1) {
- nextX = x[nextIndex];
- nextY = y[nextIndex];
- } else {
- nextX = AVE(px, x[nextIndex]);
- nextY = AVE(py, y[nextIndex]);
- }
- if (this->ppx != nextX || this->ppy != nextY) {
- double dx1, dy1, dx2, dy2, dx3, dy3;
- const double prec = 1e-6;
- TransformF26Dot6PointFloat(&p1, (prevX + (px << 1)) / 3, (prevY + (py << 1)) / 3, m);
- TransformF26Dot6PointFloat(&p2, (nextX + (px << 1)) / 3, (nextY + (py << 1)) / 3, m);
- TransformF26Dot6PointFloat(&p3, nextX, nextY, m);
- dx1 = p1.x - p0.x, dy1 = p1.y - p0.y;
- dx2 = p2.x - p0.x, dy2 = p2.y - p0.y;
- dx3 = p3.x - p0.x, dy3 = p3.y - p0.y;
- if (fabs(dx1 * dy3 - dy1 * dx3) > prec * fabs(dx1 * dx3 - dy1 * dy3) ||
- fabs(dx2 * dy3 - dy2 * dx3) > prec * fabs(dx2 * dx3 - dy2 * dy3))
- exp->CurveTo(exp, &p1, &p2, &p3);
- else
- exp->LineTo(exp, &p3);
- this->ppx = nextX; this->ppy = nextY;
- p0 = p3;
- }
- }
- }
- exp->Close(exp);
- }
- x += pts;
- y += pts;
- onCurve += pts;
- sp = *endP++;
- }
- }
- FontError ttfOutliner__Outline(ttfOutliner *this, int glyphIndex,
- float orig_x, float orig_y, FloatMatrix *m1)
- { ttfFont *pFont = this->pFont;
- FontError error;
- this->post_transform = *m1;
- this->out.contourCount = 0;
- this->out.pointCount = 0;
- this->out.bCompound = FALSE;
- this->nPointsTotal = 0;
- this->nContoursTotal = 0;
- this->out.advance.x = this->out.advance.y = 0;
- ttfFont__StartGlyph(pFont);
- error = ttfOutliner__BuildGlyphOutline(this, glyphIndex, orig_x, orig_y, &this->out);
- ttfFont__StopGlyph(pFont);
- if (pFont->nUnitsPerEm <= 0)
- pFont->nUnitsPerEm = 1024;
- if (pFont->design_grid) {
- this->post_transform.a /= pFont->nUnitsPerEm;
- this->post_transform.b /= pFont->nUnitsPerEm;
- this->post_transform.c /= pFont->nUnitsPerEm;
- this->post_transform.d /= pFont->nUnitsPerEm;
- }
- if (error != fNoError && error != fPatented)
- return error;
- return error;
- }
|