2 |
- |
1 |
/* Copyright (C) 2003 Aladdin Enterprises. All rights reserved.
|
|
|
2 |
|
|
|
3 |
This software is provided AS-IS with no warranty, either express or
|
|
|
4 |
implied.
|
|
|
5 |
|
|
|
6 |
This software is distributed under license and may not be copied,
|
|
|
7 |
modified or distributed except as expressly authorized under the terms
|
|
|
8 |
of the license contained in the file LICENSE in this distribution.
|
|
|
9 |
|
|
|
10 |
For more information about licensing, please refer to
|
|
|
11 |
http://www.ghostscript.com/licensing/. For information on
|
|
|
12 |
commercial licensing, go to http://www.artifex.com/licensing/ or
|
|
|
13 |
contact Artifex Software, Inc., 101 Lucas Valley Road #110,
|
|
|
14 |
San Rafael, CA 94903, U.S.A., +1(415)492-9861.
|
|
|
15 |
*/
|
|
|
16 |
|
|
|
17 |
/* $Id: ttfmain.c,v 1.34 2005/08/02 11:12:32 igor Exp $ */
|
|
|
18 |
/* A Free Type interface adapter. */
|
|
|
19 |
/* Uses code fragments from the FreeType project. */
|
|
|
20 |
|
|
|
21 |
#include "ttmisc.h"
|
|
|
22 |
#include "ttfoutl.h"
|
|
|
23 |
#include "ttfmemd.h"
|
|
|
24 |
|
|
|
25 |
#include "ttfinp.h"
|
|
|
26 |
#include "ttfsfnt.h"
|
|
|
27 |
#include "ttobjs.h"
|
|
|
28 |
#include "ttinterp.h"
|
|
|
29 |
#include "ttcalc.h"
|
|
|
30 |
|
|
|
31 |
private const bool skip_instructions = 0; /* Debug purpose only. */
|
|
|
32 |
|
|
|
33 |
typedef struct {
|
|
|
34 |
Fixed a, b, c, d, tx, ty;
|
|
|
35 |
} FixMatrix;
|
|
|
36 |
|
|
|
37 |
struct ttfSubGlyphUsage_s {
|
|
|
38 |
FixMatrix m;
|
|
|
39 |
int index;
|
|
|
40 |
int flags;
|
|
|
41 |
short arg1, arg2;
|
|
|
42 |
};
|
|
|
43 |
|
|
|
44 |
/*------------------------------------------------------------------- */
|
|
|
45 |
|
|
|
46 |
private Fixed AVE(F26Dot6 a, F26Dot6 b)
|
|
|
47 |
{ return (a + b) / 2;
|
|
|
48 |
}
|
|
|
49 |
|
|
|
50 |
private F26Dot6 shortToF26Dot6(short a)
|
|
|
51 |
{ return (F26Dot6)a << 6;
|
|
|
52 |
}
|
|
|
53 |
|
|
|
54 |
private F26Dot6 floatToF26Dot6(float a)
|
|
|
55 |
{ return (F26Dot6)(a * (1 << 6) + 0.5);
|
|
|
56 |
}
|
|
|
57 |
|
|
|
58 |
private Fixed floatToF16Dot16(float a)
|
|
|
59 |
{ return (F26Dot6)(a * (1 << 16) + 0.5);
|
|
|
60 |
}
|
|
|
61 |
|
|
|
62 |
private void TransformF26Dot6PointFix(F26Dot6Point *pt, F26Dot6 dx, F26Dot6 dy, FixMatrix *m)
|
|
|
63 |
{ pt->x = MulDiv(dx, m->a, 65536) + MulDiv(dy, m->c, 65536) + (m->tx >> 10);
|
|
|
64 |
pt->y = MulDiv(dx, m->b, 65536) + MulDiv(dy, m->d, 65536) + (m->ty >> 10);
|
|
|
65 |
}
|
|
|
66 |
|
|
|
67 |
private void TransformF26Dot6PointFloat(FloatPoint *pt, F26Dot6 dx, F26Dot6 dy, FloatMatrix *m)
|
|
|
68 |
{ pt->x = dx * m->a / 64 + dy * m->c / 64 + m->tx;
|
|
|
69 |
pt->y = dx * m->b / 64 + dy * m->d / 64 + m->ty;
|
|
|
70 |
}
|
|
|
71 |
|
|
|
72 |
/*-------------------------------------------------------------------*/
|
|
|
73 |
|
|
|
74 |
private ttfPtrElem *ttfFont__get_table_ptr(ttfFont *f, char *id)
|
|
|
75 |
{
|
|
|
76 |
if (!memcmp(id, "cvt ", 4))
|
|
|
77 |
return &f->t_cvt_;
|
|
|
78 |
if (!memcmp(id, "fpgm", 4))
|
|
|
79 |
return &f->t_fpgm;
|
|
|
80 |
if (!memcmp(id, "glyf", 4))
|
|
|
81 |
return &f->t_glyf;
|
|
|
82 |
if (!memcmp(id, "head", 4))
|
|
|
83 |
return &f->t_head;
|
|
|
84 |
if (!memcmp(id, "hhea", 4))
|
|
|
85 |
return &f->t_hhea;
|
|
|
86 |
if (!memcmp(id, "hmtx", 4))
|
|
|
87 |
return &f->t_hmtx;
|
|
|
88 |
if (!memcmp(id, "vhea", 4))
|
|
|
89 |
return &f->t_vhea;
|
|
|
90 |
if (!memcmp(id, "vmtx", 4))
|
|
|
91 |
return &f->t_vmtx;
|
|
|
92 |
if (!memcmp(id, "loca", 4))
|
|
|
93 |
return &f->t_loca;
|
|
|
94 |
if (!memcmp(id, "maxp", 4))
|
|
|
95 |
return &f->t_maxp;
|
|
|
96 |
if (!memcmp(id, "prep", 4))
|
|
|
97 |
return &f->t_prep;
|
|
|
98 |
if (!memcmp(id, "cmap", 4))
|
|
|
99 |
return &f->t_cmap;
|
|
|
100 |
return 0;
|
|
|
101 |
}
|
|
|
102 |
|
|
|
103 |
/*-------------------------------------------------------------------*/
|
|
|
104 |
|
|
|
105 |
TT_Error TT_Set_Instance_CharSizes(TT_Instance instance,
|
|
|
106 |
TT_F26Dot6 charWidth,
|
|
|
107 |
TT_F26Dot6 charHeight)
|
|
|
108 |
{
|
|
|
109 |
PInstance ins = instance.z;
|
|
|
110 |
|
|
|
111 |
if ( !ins )
|
|
|
112 |
return TT_Err_Invalid_Instance_Handle;
|
|
|
113 |
|
|
|
114 |
if (charWidth < 1*64)
|
|
|
115 |
charWidth = 1*64;
|
|
|
116 |
|
|
|
117 |
if (charHeight < 1*64)
|
|
|
118 |
charHeight = 1*64;
|
|
|
119 |
|
|
|
120 |
ins->metrics.x_scale1 = charWidth;
|
|
|
121 |
ins->metrics.y_scale1 = charHeight;
|
|
|
122 |
ins->metrics.x_scale2 = ins->face->font->nUnitsPerEm;
|
|
|
123 |
ins->metrics.y_scale2 = ins->face->font->nUnitsPerEm;
|
|
|
124 |
|
|
|
125 |
if (ins->face->font->nFlags & 8) {
|
|
|
126 |
ins->metrics.x_scale1 = (ins->metrics.x_scale1+32) & -64;
|
|
|
127 |
ins->metrics.y_scale1 = (ins->metrics.y_scale1+32) & -64;
|
|
|
128 |
}
|
|
|
129 |
|
|
|
130 |
ins->metrics.x_ppem = ins->metrics.x_scale1 / 64;
|
|
|
131 |
ins->metrics.y_ppem = ins->metrics.y_scale1 / 64;
|
|
|
132 |
|
|
|
133 |
if (charWidth > charHeight)
|
|
|
134 |
ins->metrics.pointSize = charWidth;
|
|
|
135 |
else
|
|
|
136 |
ins->metrics.pointSize = charHeight;
|
|
|
137 |
|
|
|
138 |
ins->valid = FALSE;
|
|
|
139 |
return Instance_Reset(ins, FALSE);
|
|
|
140 |
}
|
|
|
141 |
|
|
|
142 |
/*-------------------------------------------------------------------*/
|
|
|
143 |
|
|
|
144 |
int ttfInterpreter__obtain(ttfMemory *mem, ttfInterpreter **ptti)
|
|
|
145 |
{
|
|
|
146 |
ttfInterpreter *tti;
|
|
|
147 |
|
|
|
148 |
if (*ptti) {
|
|
|
149 |
(*ptti)->lock++;
|
|
|
150 |
return 0;
|
|
|
151 |
}
|
|
|
152 |
tti = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_ttfInterpreter, "ttfInterpreter__obtain");
|
|
|
153 |
if (!tti)
|
|
|
154 |
return fMemoryError;
|
|
|
155 |
tti->usage = 0;
|
|
|
156 |
tti->usage_size = 0;
|
|
|
157 |
tti->ttf_memory = mem;
|
|
|
158 |
tti->lock = 1;
|
|
|
159 |
tti->exec = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_TExecution_Context, "ttfInterpreter__obtain");
|
|
|
160 |
if (!tti->exec) {
|
|
|
161 |
mem->free(mem, tti, "ttfInterpreter__obtain");
|
|
|
162 |
return fMemoryError;
|
|
|
163 |
}
|
|
|
164 |
memset(tti->exec, 0, sizeof(*tti->exec));
|
|
|
165 |
*ptti = tti;
|
|
|
166 |
return 0;
|
|
|
167 |
}
|
|
|
168 |
|
|
|
169 |
void ttfInterpreter__release(ttfInterpreter **ptti)
|
|
|
170 |
{
|
|
|
171 |
ttfInterpreter *tti = *ptti;
|
|
|
172 |
ttfMemory *mem = tti->ttf_memory;
|
|
|
173 |
|
|
|
174 |
if(--tti->lock)
|
|
|
175 |
return;
|
|
|
176 |
mem->free(mem, tti->usage, "ttfInterpreter__release");
|
|
|
177 |
mem->free(mem, tti->exec, "ttfInterpreter__release");
|
|
|
178 |
mem->free(mem, *ptti, "ttfInterpreter__release");
|
|
|
179 |
mem->free(mem, mem, "ttfInterpreter__release");
|
|
|
180 |
*ptti = 0;
|
|
|
181 |
}
|
|
|
182 |
|
|
|
183 |
/*-------------------------------------------------------------------*/
|
|
|
184 |
|
|
|
185 |
void ttfFont__init(ttfFont *this, ttfMemory *mem,
|
|
|
186 |
void (*DebugRepaint)(ttfFont *),
|
|
|
187 |
int (*DebugPrint)(ttfFont *, const char *s, ...))
|
|
|
188 |
{
|
|
|
189 |
memset(this, 0, sizeof(*this));
|
|
|
190 |
this->DebugRepaint = DebugRepaint;
|
|
|
191 |
this->DebugPrint = DebugPrint;
|
|
|
192 |
}
|
|
|
193 |
|
|
|
194 |
void ttfFont__finit(ttfFont *this)
|
|
|
195 |
{ ttfMemory *mem = this->tti->ttf_memory;
|
|
|
196 |
|
|
|
197 |
if (this->exec)
|
|
|
198 |
Context_Destroy(this->exec);
|
|
|
199 |
this->exec = NULL;
|
|
|
200 |
if (this->inst)
|
|
|
201 |
Instance_Destroy(this->inst);
|
|
|
202 |
mem->free(mem, this->inst, "ttfFont__finit");
|
|
|
203 |
this->inst = NULL;
|
|
|
204 |
if (this->face)
|
|
|
205 |
Face_Destroy(this->face);
|
|
|
206 |
mem->free(mem, this->face, "ttfFont__finit");
|
|
|
207 |
this->face = NULL;
|
|
|
208 |
}
|
|
|
209 |
|
|
|
210 |
#define MAX_SUBGLYPH_NESTING 3 /* Arbitrary. We need this because we don't want
|
|
|
211 |
a ttfOutliner__BuildGlyphOutline recursion
|
|
|
212 |
while a glyph is loaded in ttfReader. */
|
|
|
213 |
|
|
|
214 |
FontError ttfFont__Open(ttfInterpreter *tti, ttfFont *this, ttfReader *r,
|
|
|
215 |
unsigned int nTTC, float w, float h,
|
|
|
216 |
bool design_grid)
|
|
|
217 |
{ char sVersion[4], sVersion0[4] = {0, 1, 0, 0};
|
|
|
218 |
unsigned int nNumTables, i;
|
|
|
219 |
TT_Error code;
|
|
|
220 |
int k;
|
|
|
221 |
TT_Instance I;
|
|
|
222 |
ttfMemory *mem = tti->ttf_memory;
|
|
|
223 |
F26Dot6 ww, hh;
|
|
|
224 |
|
|
|
225 |
this->tti = tti;
|
|
|
226 |
this->design_grid = design_grid;
|
|
|
227 |
r->Read(r, sVersion, 4);
|
|
|
228 |
if(!memcmp(sVersion, "ttcf", 4)) {
|
|
|
229 |
unsigned int nFonts;
|
|
|
230 |
unsigned int nPos = 0xbaadf00d; /* Quiet compiler. */
|
|
|
231 |
|
|
|
232 |
r->Read(r, sVersion, 4);
|
|
|
233 |
if(memcmp(sVersion, sVersion0, 4))
|
|
|
234 |
return fUnimplemented;
|
|
|
235 |
nFonts = ttfReader__UInt(r);
|
|
|
236 |
if (nFonts == 0)
|
|
|
237 |
return fBadFontData;
|
|
|
238 |
if(nTTC >= nFonts)
|
|
|
239 |
return fTableNotFound;
|
|
|
240 |
for(i = 0; i <= nTTC; i++)
|
|
|
241 |
nPos = ttfReader__UInt(r);
|
|
|
242 |
r->Seek(r, nPos);
|
|
|
243 |
r->Read(r, sVersion, 4);
|
|
|
244 |
}
|
|
|
245 |
if(memcmp(sVersion, sVersion0, 4) && memcmp(sVersion, "true", 4))
|
|
|
246 |
return fUnimplemented;
|
|
|
247 |
nNumTables = ttfReader__UShort(r);
|
|
|
248 |
ttfReader__UShort(r); /* nSearchRange */
|
|
|
249 |
ttfReader__UShort(r); /* nEntrySelector */
|
|
|
250 |
ttfReader__UShort(r); /* nRangeShift */
|
|
|
251 |
for (i = 0; i < nNumTables; i++) {
|
|
|
252 |
char sTag[5];
|
|
|
253 |
unsigned int nOffset, nLength;
|
|
|
254 |
ttfPtrElem *e;
|
|
|
255 |
|
|
|
256 |
sTag[4] = 0;
|
|
|
257 |
r->Read(r, sTag, 4);
|
|
|
258 |
ttfReader__UInt(r); /* nCheckSum */
|
|
|
259 |
nOffset = ttfReader__UInt(r);
|
|
|
260 |
nLength = ttfReader__UInt(r);
|
|
|
261 |
e = ttfFont__get_table_ptr(this, sTag);
|
|
|
262 |
if (e != NULL) {
|
|
|
263 |
e->nPos = nOffset;
|
|
|
264 |
e->nLen = nLength;
|
|
|
265 |
}
|
|
|
266 |
}
|
|
|
267 |
r->Seek(r, this->t_head.nPos + offset_of(sfnt_FontHeader, flags));
|
|
|
268 |
this->nFlags = ttfReader__UShort(r);
|
|
|
269 |
r->Seek(r, this->t_head.nPos + offset_of(sfnt_FontHeader, unitsPerEm));
|
|
|
270 |
this->nUnitsPerEm = ttfReader__UShort(r);
|
|
|
271 |
r->Seek(r, this->t_head.nPos + offset_of(sfnt_FontHeader, indexToLocFormat));
|
|
|
272 |
this->nIndexToLocFormat = ttfReader__UShort(r);
|
|
|
273 |
r->Seek(r, this->t_maxp.nPos + offset_of(sfnt_maxProfileTable, numGlyphs));
|
|
|
274 |
this->nNumGlyphs = ttfReader__UShort(r);
|
|
|
275 |
r->Seek(r, this->t_maxp.nPos + offset_of(sfnt_maxProfileTable, maxComponentElements));
|
|
|
276 |
this->nMaxComponents = ttfReader__UShort(r);
|
|
|
277 |
if(this->nMaxComponents < 10)
|
|
|
278 |
this->nMaxComponents = 10; /* work around DynaLab bug in lgoth.ttf */
|
|
|
279 |
r->Seek(r, this->t_hhea.nPos + offset_of(sfnt_MetricsHeader, numberLongMetrics));
|
|
|
280 |
this->nLongMetricsHorz = ttfReader__UShort(r);
|
|
|
281 |
if (this->t_vhea.nPos != 0) {
|
|
|
282 |
r->Seek(r, this->t_vhea.nPos + offset_of(sfnt_MetricsHeader, numberLongMetrics));
|
|
|
283 |
this->nLongMetricsVert = ttfReader__UShort(r);
|
|
|
284 |
} else
|
|
|
285 |
this->nLongMetricsVert = 0;
|
|
|
286 |
if (tti->usage_size < this->nMaxComponents * MAX_SUBGLYPH_NESTING) {
|
|
|
287 |
tti->ttf_memory->free(tti->ttf_memory, tti->usage, "ttfFont__Open");
|
|
|
288 |
tti->usage_size = 0;
|
|
|
289 |
tti->usage = mem->alloc_bytes(mem,
|
|
|
290 |
sizeof(ttfSubGlyphUsage) * this->nMaxComponents * MAX_SUBGLYPH_NESTING,
|
|
|
291 |
"ttfFont__Open");
|
|
|
292 |
if (tti->usage == NULL)
|
|
|
293 |
return fMemoryError;
|
|
|
294 |
tti->usage_size = this->nMaxComponents * MAX_SUBGLYPH_NESTING;
|
|
|
295 |
}
|
|
|
296 |
this->face = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_TFace, "ttfFont__Open");
|
|
|
297 |
if (this->face == NULL)
|
|
|
298 |
return fMemoryError;
|
|
|
299 |
memset(this->face, 0, sizeof(*this->face));
|
|
|
300 |
this->face->r = r;
|
|
|
301 |
this->face->font = this;
|
|
|
302 |
this->exec = tti->exec;
|
|
|
303 |
code = Face_Create(this->face);
|
|
|
304 |
if (code)
|
|
|
305 |
return fMemoryError;
|
|
|
306 |
code = r->Error(r);
|
|
|
307 |
if (code < 0)
|
|
|
308 |
return fBadFontData;
|
|
|
309 |
this->inst = mem->alloc_struct(mem, (const ttfMemoryDescriptor *)&st_TInstance, "ttfFont__Open");
|
|
|
310 |
if (this->inst == NULL)
|
|
|
311 |
return fMemoryError;
|
|
|
312 |
memset(this->inst, 0, sizeof(*this->inst));
|
|
|
313 |
code = Context_Create(this->exec, this->face); /* See comment in the implementation of Context_Create. */
|
|
|
314 |
if (code == TT_Err_Out_Of_Memory)
|
|
|
315 |
return fMemoryError;
|
|
|
316 |
code = Instance_Create(this->inst, this->face);
|
|
|
317 |
if (code == TT_Err_Out_Of_Memory)
|
|
|
318 |
return fMemoryError;
|
|
|
319 |
if (code)
|
|
|
320 |
return fBadFontData;
|
|
|
321 |
for(k = 0; k < this->face->cvtSize; k++)
|
|
|
322 |
this->inst->cvt[k] = shortToF26Dot6(this->face->cvt[k]);
|
|
|
323 |
code = Instance_Init(this->inst);
|
|
|
324 |
if (code == TT_Err_Out_Of_Memory)
|
|
|
325 |
return fMemoryError;
|
|
|
326 |
if (code >= TT_Err_Invalid_Opcode && code <= TT_Err_Invalid_Displacement)
|
|
|
327 |
return fBadInstruction;
|
|
|
328 |
if (code)
|
|
|
329 |
return fBadFontData;
|
|
|
330 |
I.z = this->inst;
|
|
|
331 |
if (design_grid)
|
|
|
332 |
ww = hh = shortToF26Dot6(this->nUnitsPerEm);
|
|
|
333 |
else {
|
|
|
334 |
/* Round towards zero for a better view of mirrored characters : */
|
|
|
335 |
ww = floatToF26Dot6(w);
|
|
|
336 |
hh = floatToF26Dot6(h);
|
|
|
337 |
}
|
|
|
338 |
code = TT_Set_Instance_CharSizes(I, ww, hh);
|
|
|
339 |
this->inst->metrics = this->exec->metrics;
|
|
|
340 |
if (code == TT_Err_Invalid_Engine)
|
|
|
341 |
return fPatented;
|
|
|
342 |
if (code == TT_Err_Out_Of_Memory)
|
|
|
343 |
return fMemoryError;
|
|
|
344 |
if (code >= TT_Err_Invalid_Opcode && code <= TT_Err_Invalid_Displacement)
|
|
|
345 |
return fBadInstruction;
|
|
|
346 |
if (code)
|
|
|
347 |
return fBadFontData;
|
|
|
348 |
return code;
|
|
|
349 |
}
|
|
|
350 |
|
|
|
351 |
private void ttfFont__StartGlyph(ttfFont *this)
|
|
|
352 |
{ Context_Load( this->exec, this->inst );
|
|
|
353 |
if ( this->inst->GS.instruct_control & 2 )
|
|
|
354 |
this->exec->GS = Default_GraphicsState;
|
|
|
355 |
else
|
|
|
356 |
this->exec->GS = this->inst->GS;
|
|
|
357 |
this->tti->usage_top = 0;
|
|
|
358 |
}
|
|
|
359 |
|
|
|
360 |
private void ttfFont__StopGlyph(ttfFont *this)
|
|
|
361 |
{
|
|
|
362 |
Context_Save(this->exec, this->inst);
|
|
|
363 |
}
|
|
|
364 |
|
|
|
365 |
/*-------------------------------------------------------------------*/
|
|
|
366 |
|
|
|
367 |
private void mount_zone( PGlyph_Zone source,
|
|
|
368 |
PGlyph_Zone target )
|
|
|
369 |
{
|
|
|
370 |
Int np, nc;
|
|
|
371 |
|
|
|
372 |
np = source->n_points;
|
|
|
373 |
nc = source->n_contours;
|
|
|
374 |
|
|
|
375 |
target->org_x = source->org_x + np;
|
|
|
376 |
target->org_y = source->org_y + np;
|
|
|
377 |
target->cur_x = source->cur_x + np;
|
|
|
378 |
target->cur_y = source->cur_y + np;
|
|
|
379 |
target->touch = source->touch + np;
|
|
|
380 |
|
|
|
381 |
target->contours = source->contours + nc;
|
|
|
382 |
|
|
|
383 |
target->n_points = 0;
|
|
|
384 |
target->n_contours = 0;
|
|
|
385 |
}
|
|
|
386 |
|
|
|
387 |
private void Init_Glyph_Component( PSubglyph_Record element,
|
|
|
388 |
PSubglyph_Record original,
|
|
|
389 |
PExecution_Context exec )
|
|
|
390 |
{
|
|
|
391 |
element->index = -1;
|
|
|
392 |
element->is_scaled = FALSE;
|
|
|
393 |
element->is_hinted = FALSE;
|
|
|
394 |
|
|
|
395 |
if (original)
|
|
|
396 |
mount_zone( &original->zone, &element->zone );
|
|
|
397 |
else
|
|
|
398 |
element->zone = exec->pts;
|
|
|
399 |
|
|
|
400 |
element->zone.n_contours = 0;
|
|
|
401 |
element->zone.n_points = 0;
|
|
|
402 |
|
|
|
403 |
element->arg1 = 0;
|
|
|
404 |
element->arg2 = 0;
|
|
|
405 |
|
|
|
406 |
element->element_flag = 0;
|
|
|
407 |
element->preserve_pps = FALSE;
|
|
|
408 |
|
|
|
409 |
element->transform.xx = 1 << 16;
|
|
|
410 |
element->transform.xy = 0;
|
|
|
411 |
element->transform.yx = 0;
|
|
|
412 |
element->transform.yy = 1 << 16;
|
|
|
413 |
|
|
|
414 |
element->transform.ox = 0;
|
|
|
415 |
element->transform.oy = 0;
|
|
|
416 |
|
|
|
417 |
element->leftBearing = 0;
|
|
|
418 |
element->advanceWidth = 0;
|
|
|
419 |
}
|
|
|
420 |
|
|
|
421 |
private void cur_to_org( Int n, PGlyph_Zone zone )
|
|
|
422 |
{
|
|
|
423 |
Int k;
|
|
|
424 |
|
|
|
425 |
for ( k = 0; k < n; k++ )
|
|
|
426 |
zone->org_x[k] = zone->cur_x[k];
|
|
|
427 |
|
|
|
428 |
for ( k = 0; k < n; k++ )
|
|
|
429 |
zone->org_y[k] = zone->cur_y[k];
|
|
|
430 |
}
|
|
|
431 |
|
|
|
432 |
private void org_to_cur( Int n, PGlyph_Zone zone )
|
|
|
433 |
{
|
|
|
434 |
Int k;
|
|
|
435 |
|
|
|
436 |
for ( k = 0; k < n; k++ )
|
|
|
437 |
zone->cur_x[k] = zone->org_x[k];
|
|
|
438 |
|
|
|
439 |
for ( k = 0; k < n; k++ )
|
|
|
440 |
zone->cur_y[k] = zone->org_y[k];
|
|
|
441 |
}
|
|
|
442 |
|
|
|
443 |
|
|
|
444 |
/*-------------------------------------------------------------------*/
|
|
|
445 |
|
|
|
446 |
void ttfOutliner__init(ttfOutliner *this, ttfFont *f, ttfReader *r, ttfExport *exp,
|
|
|
447 |
bool bOutline, bool bFirst, bool bVertical)
|
|
|
448 |
{
|
|
|
449 |
this->r = r;
|
|
|
450 |
this->bOutline = bOutline;
|
|
|
451 |
this->bFirst = bFirst;
|
|
|
452 |
this->pFont = f;
|
|
|
453 |
this->bVertical = bVertical;
|
|
|
454 |
this->exp = exp;
|
|
|
455 |
}
|
|
|
456 |
|
|
|
457 |
private void MoveGlyphOutline(TGlyph_Zone *pts, int nOffset, ttfGlyphOutline *out, FixMatrix *m)
|
|
|
458 |
{ F26Dot6* x = pts->org_x + nOffset;
|
|
|
459 |
F26Dot6* y = pts->org_y + nOffset;
|
|
|
460 |
short count = out->pointCount;
|
|
|
461 |
F26Dot6Point p;
|
|
|
462 |
|
|
|
463 |
if (m->a == 65536 && m->b == 0 &&
|
|
|
464 |
m->c == 0 && m->d == 65536 &&
|
|
|
465 |
m->tx == 0 && m->ty == 0)
|
|
|
466 |
return;
|
|
|
467 |
for (; count != 0; --count) {
|
|
|
468 |
TransformF26Dot6PointFix(&p, *x, *y, m);
|
|
|
469 |
*x++ = p.x;
|
|
|
470 |
*y++ = p.y;
|
|
|
471 |
}
|
|
|
472 |
}
|
|
|
473 |
|
|
|
474 |
private FontError ttfOutliner__BuildGlyphOutlineAux(ttfOutliner *this, int glyphIndex,
|
|
|
475 |
FixMatrix *m_orig, ttfGlyphOutline* gOutline)
|
|
|
476 |
{ ttfFont *pFont = this->pFont;
|
|
|
477 |
ttfReader *r = this->r;
|
|
|
478 |
ttfInterpreter *tti = pFont->tti;
|
|
|
479 |
short sideBearing;
|
|
|
480 |
FontError error = fNoError;
|
|
|
481 |
short arg1, arg2;
|
|
|
482 |
short count;
|
|
|
483 |
unsigned int nMtxPos, nMtxGlyph = glyphIndex, nLongMetrics, i;
|
|
|
484 |
unsigned short nAdvance;
|
|
|
485 |
unsigned int nNextGlyphPtr = 0;
|
|
|
486 |
unsigned int nPosBeg;
|
|
|
487 |
TExecution_Context *exec = pFont->exec;
|
|
|
488 |
TGlyph_Zone *pts = &exec->pts;
|
|
|
489 |
TSubglyph_Record subglyph;
|
|
|
490 |
ttfSubGlyphUsage *usage = tti->usage + tti->usage_top;
|
|
|
491 |
const byte *glyph = NULL;
|
|
|
492 |
int glyph_size;
|
|
|
493 |
|
|
|
494 |
if(this->bVertical && pFont->t_vhea.nPos && pFont->t_vmtx.nPos) {
|
|
|
495 |
nLongMetrics = pFont->nLongMetricsVert;
|
|
|
496 |
nMtxPos = pFont->t_vmtx.nPos;
|
|
|
497 |
} else {
|
|
|
498 |
nLongMetrics = pFont->nLongMetricsHorz;
|
|
|
499 |
nMtxPos = pFont->t_hmtx.nPos;
|
|
|
500 |
}
|
|
|
501 |
if (this->bVertical && (!pFont->t_vhea.nPos || pFont->t_vmtx.nPos) && nMtxGlyph < nLongMetrics) {
|
|
|
502 |
/* A bad font fix. */
|
|
|
503 |
nMtxGlyph = nLongMetrics;
|
|
|
504 |
if(nMtxGlyph >= pFont->nNumGlyphs)
|
|
|
505 |
nMtxGlyph = pFont->nNumGlyphs - 1;
|
|
|
506 |
}
|
|
|
507 |
if (nMtxGlyph < nLongMetrics) {
|
|
|
508 |
r->Seek(r, nMtxPos + 4 * nMtxGlyph);
|
|
|
509 |
nAdvance = ttfReader__Short(r);
|
|
|
510 |
sideBearing = ttfReader__Short(r);
|
|
|
511 |
} else {
|
|
|
512 |
r->Seek(r, nMtxPos + 4 * (nLongMetrics - 1));
|
|
|
513 |
nAdvance = ttfReader__Short(r);
|
|
|
514 |
r->Seek(r, nMtxPos + 4 * nLongMetrics + 2 * (nMtxGlyph - nLongMetrics));
|
|
|
515 |
sideBearing = ttfReader__Short(r);
|
|
|
516 |
}
|
|
|
517 |
if (r->Error(r))
|
|
|
518 |
goto errex;
|
|
|
519 |
gOutline->sideBearing = shortToF26Dot6(sideBearing);
|
|
|
520 |
gOutline->advance.x = shortToF26Dot6(nAdvance);
|
|
|
521 |
gOutline->advance.y = 0;
|
|
|
522 |
this->bFirst = FALSE;
|
|
|
523 |
|
|
|
524 |
|
|
|
525 |
if (!this->bOutline)
|
|
|
526 |
return fNoError;
|
|
|
527 |
if (!r->LoadGlyph(r, glyphIndex, &glyph, &glyph_size))
|
|
|
528 |
return fGlyphNotFound;
|
|
|
529 |
if (r->Eof(r)) {
|
|
|
530 |
r->ReleaseGlyph(r, glyphIndex);
|
|
|
531 |
gOutline->xMinB = gOutline->yMinB = 0;
|
|
|
532 |
gOutline->xMaxB = gOutline->yMaxB = 0;
|
|
|
533 |
return fNoError;
|
|
|
534 |
}
|
|
|
535 |
if (r->Error(r))
|
|
|
536 |
goto errex;
|
|
|
537 |
nPosBeg = r->Tell(r);
|
|
|
538 |
|
|
|
539 |
gOutline->contourCount = ttfReader__Short(r);
|
|
|
540 |
subglyph.bbox.xMin = ttfReader__Short(r);
|
|
|
541 |
subglyph.bbox.yMin = ttfReader__Short(r);
|
|
|
542 |
subglyph.bbox.xMax = ttfReader__Short(r);
|
|
|
543 |
subglyph.bbox.yMax = ttfReader__Short(r);
|
|
|
544 |
|
|
|
545 |
gOutline->xMinB = subglyph.bbox.xMin;
|
|
|
546 |
gOutline->yMinB = subglyph.bbox.yMin;
|
|
|
547 |
gOutline->xMaxB = subglyph.bbox.xMax;
|
|
|
548 |
gOutline->yMaxB = subglyph.bbox.yMax;
|
|
|
549 |
|
|
|
550 |
/* FreeType stuff beg */
|
|
|
551 |
Init_Glyph_Component(&subglyph, NULL, pFont->exec);
|
|
|
552 |
subglyph.leftBearing = sideBearing;
|
|
|
553 |
subglyph.advanceWidth = nAdvance;
|
|
|
554 |
subglyph.pp1.x = subglyph.bbox.xMin - sideBearing;
|
|
|
555 |
subglyph.pp1.y = 0;
|
|
|
556 |
subglyph.pp2.x = subglyph.pp1.x + nAdvance;
|
|
|
557 |
subglyph.pp2.y = 0;
|
|
|
558 |
/* FreeType stuff end */
|
|
|
559 |
|
|
|
560 |
if (gOutline->contourCount == 0)
|
|
|
561 |
gOutline->pointCount = 0;
|
|
|
562 |
else if (gOutline->contourCount == -1) {
|
|
|
563 |
unsigned short flags, index, bHaveInstructions = 0;
|
|
|
564 |
unsigned int nUsage = 0;
|
|
|
565 |
unsigned int nPos;
|
|
|
566 |
unsigned int n_ins;
|
|
|
567 |
|
|
|
568 |
gOutline->bCompound = TRUE;
|
|
|
569 |
if (tti->usage_top + pFont->nMaxComponents > tti->usage_size)
|
|
|
570 |
return fBadFontData;
|
|
|
571 |
gOutline->contourCount = gOutline->pointCount = 0;
|
|
|
572 |
do {
|
|
|
573 |
FixMatrix m;
|
|
|
574 |
ttfSubGlyphUsage *e;
|
|
|
575 |
|
|
|
576 |
if (nUsage >= pFont->nMaxComponents) {
|
|
|
577 |
error = fMemoryError; goto ex;
|
|
|
578 |
}
|
|
|
579 |
flags = ttfReader__UShort(r);
|
|
|
580 |
index = ttfReader__UShort(r);
|
|
|
581 |
bHaveInstructions |= (flags & WE_HAVE_INSTRUCTIONS);
|
|
|
582 |
if (flags & ARG_1_AND_2_ARE_WORDS) {
|
|
|
583 |
arg1 = ttfReader__Short(r);
|
|
|
584 |
arg2 = ttfReader__Short(r);
|
|
|
585 |
} else {
|
|
|
586 |
if (flags & ARGS_ARE_XY_VALUES) {
|
|
|
587 |
/* offsets are signed */
|
|
|
588 |
arg1 = ttfReader__SignedByte(r);
|
|
|
589 |
arg2 = ttfReader__SignedByte(r);
|
|
|
590 |
} else { /* anchor points are unsigned */
|
|
|
591 |
arg1 = ttfReader__Byte(r);
|
|
|
592 |
arg2 = ttfReader__Byte(r);
|
|
|
593 |
}
|
|
|
594 |
}
|
|
|
595 |
m.b = m.c = m.tx = m.ty = 0;
|
|
|
596 |
if (flags & WE_HAVE_A_SCALE)
|
|
|
597 |
m.a = m.d = (Fixed)ttfReader__Short(r) << 2;
|
|
|
598 |
else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
|
|
|
599 |
m.a = (Fixed)ttfReader__Short(r) << 2;
|
|
|
600 |
m.d = (Fixed)ttfReader__Short(r) << 2;
|
|
|
601 |
} else if (flags & WE_HAVE_A_TWO_BY_TWO) {
|
|
|
602 |
m.a = (Fixed)ttfReader__Short(r)<<2;
|
|
|
603 |
m.b = (Fixed)ttfReader__Short(r)<<2;
|
|
|
604 |
m.c = (Fixed)ttfReader__Short(r)<<2;
|
|
|
605 |
m.d = (Fixed)ttfReader__Short(r)<<2;
|
|
|
606 |
} else
|
|
|
607 |
m.a = m.d = 65536;
|
|
|
608 |
e = &usage[nUsage];
|
|
|
609 |
e->m = m;
|
|
|
610 |
e->index = index;
|
|
|
611 |
e->arg1 = arg1;
|
|
|
612 |
e->arg2 = arg2;
|
|
|
613 |
e->flags = flags;
|
|
|
614 |
nUsage++;
|
|
|
615 |
} while (flags & MORE_COMPONENTS);
|
|
|
616 |
/* Some fonts have bad WE_HAVE_INSTRUCTIONS, so use nNextGlyphPtr : */
|
|
|
617 |
if (r->Error(r))
|
|
|
618 |
goto errex;
|
|
|
619 |
nPos = r->Tell(r);
|
|
|
620 |
n_ins = ((!r->Eof(r) && (bHaveInstructions || nPos < nNextGlyphPtr)) ? ttfReader__UShort(r) : 0);
|
|
|
621 |
nPos = r->Tell(r);
|
|
|
622 |
r->ReleaseGlyph(r, glyphIndex);
|
|
|
623 |
glyph = NULL;
|
|
|
624 |
for (i = 0; i < nUsage; i++) {
|
|
|
625 |
ttfGlyphOutline out;
|
|
|
626 |
ttfSubGlyphUsage *e = &usage[i];
|
|
|
627 |
int j;
|
|
|
628 |
TT_Error code;
|
|
|
629 |
int nPointsStored = this->nPointsTotal, nContoursStored = this->nContoursTotal;
|
|
|
630 |
|
|
|
631 |
out.contourCount = 0;
|
|
|
632 |
out.pointCount = 0;
|
|
|
633 |
out.bCompound = FALSE;
|
|
|
634 |
pts->org_x += nPointsStored;
|
|
|
635 |
pts->org_y += nPointsStored;
|
|
|
636 |
pts->cur_x += nPointsStored;
|
|
|
637 |
pts->cur_y += nPointsStored;
|
|
|
638 |
pts->touch += nPointsStored;
|
|
|
639 |
pts->contours += nContoursStored;
|
|
|
640 |
tti->usage_top += nUsage;
|
|
|
641 |
code = ttfOutliner__BuildGlyphOutlineAux(this, e->index, m_orig, &out);
|
|
|
642 |
pts->org_x -= nPointsStored;
|
|
|
643 |
pts->org_y -= nPointsStored;
|
|
|
644 |
pts->cur_x -= nPointsStored;
|
|
|
645 |
pts->cur_y -= nPointsStored;
|
|
|
646 |
pts->touch -= nPointsStored;
|
|
|
647 |
tti->usage_top -= nUsage;
|
|
|
648 |
pts->contours -= nContoursStored;
|
|
|
649 |
if (code == fPatented)
|
|
|
650 |
error = code;
|
|
|
651 |
else if (code != fNoError) {
|
|
|
652 |
error = code;
|
|
|
653 |
goto ex;
|
|
|
654 |
}
|
|
|
655 |
if (flags & ARGS_ARE_XY_VALUES) {
|
|
|
656 |
e->m.tx = Scale_X( &exec->metrics, e->arg1 ) << 10;
|
|
|
657 |
e->m.ty = Scale_Y( &exec->metrics, e->arg2 ) << 10;
|
|
|
658 |
} else {
|
|
|
659 |
e->m.tx = (pts->org_x[e->arg1] - pts->org_x[gOutline->pointCount + e->arg2]) << 10;
|
|
|
660 |
e->m.ty = (pts->org_y[e->arg1] - pts->org_y[gOutline->pointCount + e->arg2]) << 10;
|
|
|
661 |
}
|
|
|
662 |
MoveGlyphOutline(pts, nPointsStored, &out, &e->m);
|
|
|
663 |
for (j = nContoursStored; j < out.contourCount + nContoursStored; j++)
|
|
|
664 |
pts->contours[j] += nPointsStored;
|
|
|
665 |
gOutline->contourCount += out.contourCount;
|
|
|
666 |
gOutline->pointCount += out.pointCount;
|
|
|
667 |
if(e->flags & USE_MY_METRICS) {
|
|
|
668 |
gOutline->advance.x = out.advance.x;
|
|
|
669 |
gOutline->sideBearing = out.sideBearing;
|
|
|
670 |
}
|
|
|
671 |
}
|
|
|
672 |
if (!skip_instructions && n_ins &&
|
|
|
673 |
!(pFont->inst->GS.instruct_control & 1)) {
|
|
|
674 |
TT_Error code;
|
|
|
675 |
|
|
|
676 |
r->LoadGlyph(r, glyphIndex, &glyph, &glyph_size);
|
|
|
677 |
if (r->Error(r))
|
|
|
678 |
goto errex;
|
|
|
679 |
if (nPos + n_ins > glyph_size)
|
|
|
680 |
goto errex;
|
|
|
681 |
code = Set_CodeRange(exec, TT_CodeRange_Glyph, (byte *)glyph + nPos, n_ins);
|
|
|
682 |
if (!code) {
|
|
|
683 |
int nPoints = gOutline->pointCount + 2;
|
|
|
684 |
int k;
|
|
|
685 |
F26Dot6 x;
|
|
|
686 |
|
|
|
687 |
exec->pts = subglyph.zone;
|
|
|
688 |
pts->n_points = nPoints;
|
|
|
689 |
pts->n_contours = gOutline->contourCount;
|
|
|
690 |
/* add phantom points : */
|
|
|
691 |
pts->org_x[nPoints - 2] = Scale_X(&exec->metrics, subglyph.pp1.x);
|
|
|
692 |
pts->org_y[nPoints - 2] = Scale_Y(&exec->metrics, subglyph.pp1.y);
|
|
|
693 |
pts->org_x[nPoints - 1] = Scale_X(&exec->metrics, subglyph.pp2.x);
|
|
|
694 |
pts->org_y[nPoints - 1] = Scale_Y(&exec->metrics, subglyph.pp2.y);
|
|
|
695 |
pts->touch[nPoints - 1] = 0;
|
|
|
696 |
pts->touch[nPoints - 2] = 0;
|
|
|
697 |
/* if hinting, round the phantom points (not sure) : */
|
|
|
698 |
x = pts->org_x[nPoints - 2];
|
|
|
699 |
x = ((x + 32) & -64) - x;
|
|
|
700 |
if (x)
|
|
|
701 |
for (k = 0; k < nPoints; k++)
|
|
|
702 |
pts->org_x[k] += x;
|
|
|
703 |
pts->cur_x[nPoints - 1] = (pts->cur_x[nPoints - 1] + 32) & -64;
|
|
|
704 |
for (k = 0; k < nPoints; k++)
|
|
|
705 |
pts->touch[k] = pts->touch[k] & TT_Flag_On_Curve;
|
|
|
706 |
org_to_cur(nPoints, pts);
|
|
|
707 |
exec->is_composite = TRUE;
|
|
|
708 |
if (pFont->patented)
|
|
|
709 |
code = TT_Err_Invalid_Engine;
|
|
|
710 |
else
|
|
|
711 |
code = Context_Run(exec, FALSE);
|
|
|
712 |
if (!code)
|
|
|
713 |
cur_to_org(nPoints, pts);
|
|
|
714 |
else if (code == TT_Err_Invalid_Engine)
|
|
|
715 |
error = fPatented;
|
|
|
716 |
else
|
|
|
717 |
error = fBadFontData;
|
|
|
718 |
}
|
|
|
719 |
Unset_CodeRange(exec);
|
|
|
720 |
Clear_CodeRange(exec, TT_CodeRange_Glyph);
|
|
|
721 |
}
|
|
|
722 |
} else if (gOutline->contourCount > 0) {
|
|
|
723 |
uint16 i;
|
|
|
724 |
int nPoints;
|
|
|
725 |
bool bInsOK;
|
|
|
726 |
byte *onCurve, *stop, flag;
|
|
|
727 |
short *endPoints;
|
|
|
728 |
unsigned int nPos;
|
|
|
729 |
unsigned int n_ins;
|
|
|
730 |
|
|
|
731 |
if (this->nContoursTotal + gOutline->contourCount > exec->n_contours) {
|
|
|
732 |
error = fBadFontData; goto ex;
|
|
|
733 |
}
|
|
|
734 |
endPoints = pts->contours;
|
|
|
735 |
for (i = 0; i < gOutline->contourCount; i++)
|
|
|
736 |
endPoints[i] = ttfReader__Short(r);
|
|
|
737 |
for (i = 1; i < gOutline->contourCount; i++)
|
|
|
738 |
if (endPoints[i - 1] >= endPoints[i]) {
|
|
|
739 |
error = fBadFontData; goto ex;
|
|
|
740 |
}
|
|
|
741 |
nPoints = gOutline->pointCount = endPoints[gOutline->contourCount - 1] + 1;
|
|
|
742 |
if (this->nPointsTotal + nPoints + 2 > exec->n_points) {
|
|
|
743 |
error = fBadFontData; goto ex;
|
|
|
744 |
}
|
|
|
745 |
n_ins = ttfReader__Short(r);
|
|
|
746 |
nPos = r->Tell(r);
|
|
|
747 |
r->Seek(r, nPos + n_ins);
|
|
|
748 |
if (r->Error(r))
|
|
|
749 |
goto errex;
|
|
|
750 |
bInsOK = !Set_CodeRange(exec, TT_CodeRange_Glyph, (byte *)glyph + nPos, n_ins);
|
|
|
751 |
onCurve = pts->touch;
|
|
|
752 |
stop = onCurve + gOutline->pointCount;
|
|
|
753 |
|
|
|
754 |
while (onCurve < stop) {
|
|
|
755 |
*onCurve++ = flag = ttfReader__Byte(r);
|
|
|
756 |
if (flag & REPEAT_FLAGS) {
|
|
|
757 |
count = ttfReader__Byte(r);
|
|
|
758 |
for (--count; count >= 0; --count)
|
|
|
759 |
*onCurve++ = flag;
|
|
|
760 |
}
|
|
|
761 |
}
|
|
|
762 |
/* Lets do X */
|
|
|
763 |
{ short coord = (this->bVertical ? 0 : sideBearing - subglyph.bbox.xMin);
|
|
|
764 |
F26Dot6* x = pts->org_x;
|
|
|
765 |
onCurve = pts->touch;
|
|
|
766 |
while (onCurve < stop) {
|
|
|
767 |
if ((flag = *onCurve++) & XSHORT) {
|
|
|
768 |
if (flag & SHORT_X_IS_POS)
|
|
|
769 |
coord += ttfReader__Byte(r);
|
|
|
770 |
else
|
|
|
771 |
coord -= ttfReader__Byte(r);
|
|
|
772 |
} else if (!(flag & NEXT_X_IS_ZERO))
|
|
|
773 |
coord += ttfReader__Short(r);
|
|
|
774 |
*x++ = Scale_X(&exec->metrics, coord);
|
|
|
775 |
}
|
|
|
776 |
}
|
|
|
777 |
/* Lets do Y */
|
|
|
778 |
{ short coord = 0;
|
|
|
779 |
F26Dot6* y = pts->org_y;
|
|
|
780 |
onCurve = pts->touch;
|
|
|
781 |
while (onCurve < stop) {
|
|
|
782 |
if((flag = *onCurve) & YSHORT)
|
|
|
783 |
if ( flag & SHORT_Y_IS_POS )
|
|
|
784 |
coord += ttfReader__Byte(r);
|
|
|
785 |
else
|
|
|
786 |
coord -= ttfReader__Byte(r);
|
|
|
787 |
else if(!(flag & NEXT_Y_IS_ZERO))
|
|
|
788 |
coord += ttfReader__Short(r);
|
|
|
789 |
*y++ = Scale_Y( &exec->metrics, coord );
|
|
|
790 |
|
|
|
791 |
/* Filter off the extra bits */
|
|
|
792 |
*onCurve++ = flag & ONCURVE;
|
|
|
793 |
}
|
|
|
794 |
}
|
|
|
795 |
MoveGlyphOutline(pts, 0, gOutline, m_orig);
|
|
|
796 |
this->nContoursTotal += gOutline->contourCount;
|
|
|
797 |
this->nPointsTotal += nPoints;
|
|
|
798 |
if (!skip_instructions &&
|
|
|
799 |
!r->Error(r) && n_ins && bInsOK && !(pFont->inst->GS.instruct_control & 1)) {
|
|
|
800 |
TGlyph_Zone *pts = &exec->pts;
|
|
|
801 |
int k;
|
|
|
802 |
F26Dot6 x;
|
|
|
803 |
TT_Error code;
|
|
|
804 |
|
|
|
805 |
exec->is_composite = FALSE;
|
|
|
806 |
/* add phantom points : */
|
|
|
807 |
pts->org_x[nPoints ] = Scale_X(&exec->metrics, subglyph.pp1.x);
|
|
|
808 |
pts->org_y[nPoints ] = Scale_Y(&exec->metrics, subglyph.pp1.y);
|
|
|
809 |
pts->org_x[nPoints + 1] = Scale_X(&exec->metrics, subglyph.pp2.x);
|
|
|
810 |
pts->org_y[nPoints + 1] = Scale_Y(&exec->metrics, subglyph.pp2.y);
|
|
|
811 |
pts->touch[nPoints ] = 0;
|
|
|
812 |
pts->touch[nPoints + 1] = 0;
|
|
|
813 |
pts->n_points = nPoints + 2;
|
|
|
814 |
pts->n_contours = gOutline->contourCount;
|
|
|
815 |
/* if hinting, round the phantom points (not sure) : */
|
|
|
816 |
x = pts->org_x[nPoints];
|
|
|
817 |
x = ((x + 32) & -64) - x;
|
|
|
818 |
if (x)
|
|
|
819 |
for (k = 0; k < nPoints + 2; k++)
|
|
|
820 |
pts->org_x[k] += x;
|
|
|
821 |
pts->cur_x[nPoints + 1] = (pts->cur_x[nPoints + 1] + 32) & -64;
|
|
|
822 |
org_to_cur(nPoints + 2, pts);
|
|
|
823 |
exec->is_composite = FALSE;
|
|
|
824 |
for (k = 0; k < nPoints + 2; k++)
|
|
|
825 |
pts->touch[k] &= TT_Flag_On_Curve;
|
|
|
826 |
if (pFont->patented)
|
|
|
827 |
code = TT_Err_Invalid_Engine;
|
|
|
828 |
else
|
|
|
829 |
code = Context_Run(exec, FALSE );
|
|
|
830 |
if (!code)
|
|
|
831 |
cur_to_org(nPoints + 2, pts);
|
|
|
832 |
else if (code == TT_Err_Invalid_Engine)
|
|
|
833 |
error = fPatented;
|
|
|
834 |
else
|
|
|
835 |
error = fBadInstruction;
|
|
|
836 |
gOutline->sideBearing = subglyph.bbox.xMin - subglyph.pp1.x;
|
|
|
837 |
gOutline->advance.x = subglyph.pp2.x - subglyph.pp1.x;
|
|
|
838 |
}
|
|
|
839 |
Unset_CodeRange(exec);
|
|
|
840 |
Clear_CodeRange(exec, TT_CodeRange_Glyph);
|
|
|
841 |
} else
|
|
|
842 |
error = fBadFontData;
|
|
|
843 |
goto ex;
|
|
|
844 |
errex:;
|
|
|
845 |
error = fBadFontData;
|
|
|
846 |
ex:;
|
|
|
847 |
r->ReleaseGlyph(r, glyphIndex);
|
|
|
848 |
return error;
|
|
|
849 |
}
|
|
|
850 |
|
|
|
851 |
private FontError ttfOutliner__BuildGlyphOutline(ttfOutliner *this, int glyphIndex,
|
|
|
852 |
float orig_x, float orig_y, ttfGlyphOutline* gOutline)
|
|
|
853 |
{
|
|
|
854 |
FixMatrix m_orig = {1 << 16, 0, 0, 1 << 16, 0, 0};
|
|
|
855 |
|
|
|
856 |
/* Round towards zero like old character coordinate conversions do. */
|
|
|
857 |
m_orig.tx = floatToF16Dot16(orig_x);
|
|
|
858 |
m_orig.ty = floatToF16Dot16(orig_y);
|
|
|
859 |
return ttfOutliner__BuildGlyphOutlineAux(this, glyphIndex, &m_orig, gOutline);
|
|
|
860 |
}
|
|
|
861 |
|
|
|
862 |
|
|
|
863 |
#define AVECTOR_BUG 1 /* Work around a bug in AVector fonts. */
|
|
|
864 |
|
|
|
865 |
void ttfOutliner__DrawGlyphOutline(ttfOutliner *this)
|
|
|
866 |
{ ttfGlyphOutline* out = &this->out;
|
|
|
867 |
FloatMatrix *m = &this->post_transform;
|
|
|
868 |
ttfFont *pFont = this->pFont;
|
|
|
869 |
ttfExport *exp = this->exp;
|
|
|
870 |
TExecution_Context *exec = pFont->exec;
|
|
|
871 |
TGlyph_Zone *pts = &exec->pts;
|
|
|
872 |
short* endP = pts->contours;
|
|
|
873 |
byte* onCurve = pts->touch;
|
|
|
874 |
F26Dot6* x = pts->org_x;
|
|
|
875 |
F26Dot6* y = pts->org_y;
|
|
|
876 |
F26Dot6 px, py;
|
|
|
877 |
short sp, ctr;
|
|
|
878 |
FloatPoint p0, p1, p2, p3;
|
|
|
879 |
|
|
|
880 |
# if AVECTOR_BUG
|
|
|
881 |
short xMinB = out->xMinB >> 6, xMaxB=out->xMaxB >> 6;
|
|
|
882 |
short yMinB = out->yMinB >> 6, yMaxB=out->yMaxB >> 6;
|
|
|
883 |
short expand=pFont->nUnitsPerEm*2;
|
|
|
884 |
F26Dot6 xMin, xMax, yMin, yMax;
|
|
|
885 |
|
|
|
886 |
xMinB -= expand;
|
|
|
887 |
yMinB -= expand;
|
|
|
888 |
xMaxB += expand;
|
|
|
889 |
yMaxB += expand;
|
|
|
890 |
xMin = Scale_X(&exec->metrics, xMinB);
|
|
|
891 |
xMax = Scale_X(&exec->metrics, xMaxB);
|
|
|
892 |
yMin = Scale_X(&exec->metrics, yMinB);
|
|
|
893 |
yMax = Scale_X(&exec->metrics, yMaxB);
|
|
|
894 |
# endif
|
|
|
895 |
|
|
|
896 |
TransformF26Dot6PointFloat(&p1, out->advance.x, out->advance.y, m);
|
|
|
897 |
p1.x -= this->post_transform.tx;
|
|
|
898 |
p1.y -= this->post_transform.ty;
|
|
|
899 |
exp->SetWidth(exp, &p1);
|
|
|
900 |
sp = -1;
|
|
|
901 |
for (ctr = out->contourCount; ctr != 0; --ctr) {
|
|
|
902 |
short pt, pts = *endP - sp;
|
|
|
903 |
short ep = pts - 1;
|
|
|
904 |
|
|
|
905 |
if (pts < 3) {
|
|
|
906 |
x += pts;
|
|
|
907 |
y += pts;
|
|
|
908 |
onCurve += pts;
|
|
|
909 |
sp = *endP++;
|
|
|
910 |
continue; /* skip 1 and 2 point contours */
|
|
|
911 |
}
|
|
|
912 |
|
|
|
913 |
if (exp->bPoints) {
|
|
|
914 |
for (pt = 0; pt <= ep; pt++) {
|
|
|
915 |
px = x[pt], py = y[pt];
|
|
|
916 |
# if AVECTOR_BUG
|
|
|
917 |
if (x[pt] < xMin || xMax < x[pt] || y[pt] < yMin || yMax < y[pt]) {
|
|
|
918 |
short prevIndex = pt == 0 ? ep : pt - 1;
|
|
|
919 |
short nextIndex = pt == ep ? 0 : pt + 1;
|
|
|
920 |
if (nextIndex > ep)
|
|
|
921 |
nextIndex = 0;
|
|
|
922 |
px=AVE(x[prevIndex], x[nextIndex]);
|
|
|
923 |
py=AVE(y[prevIndex], y[nextIndex]);
|
|
|
924 |
}
|
|
|
925 |
# endif
|
|
|
926 |
TransformF26Dot6PointFloat(&p0, px, py, m);
|
|
|
927 |
exp->Point(exp, &p0, onCurve[pt], !pt);
|
|
|
928 |
}
|
|
|
929 |
}
|
|
|
930 |
|
|
|
931 |
if (exp->bOutline) {
|
|
|
932 |
pt = 0;
|
|
|
933 |
if(onCurve[ep] & 1) {
|
|
|
934 |
px = x[ep];
|
|
|
935 |
py = y[ep];
|
|
|
936 |
} else if (onCurve[0] & 1) {
|
|
|
937 |
px = x[0];
|
|
|
938 |
py = y[0];
|
|
|
939 |
pt = 1;
|
|
|
940 |
} else {
|
|
|
941 |
px = AVE(x[0], x[ep]);
|
|
|
942 |
py = AVE(y[0], y[ep]);
|
|
|
943 |
}
|
|
|
944 |
this->ppx = px; this->ppy = py;
|
|
|
945 |
TransformF26Dot6PointFloat(&p0, px, py, m);
|
|
|
946 |
exp->MoveTo(exp, &p0);
|
|
|
947 |
|
|
|
948 |
for (; pt <= ep; pt++) {
|
|
|
949 |
short prevIndex = pt == 0 ? ep : pt - 1;
|
|
|
950 |
short nextIndex = pt == ep ? 0 : pt + 1;
|
|
|
951 |
if (onCurve[pt] & 1) {
|
|
|
952 |
if (onCurve[prevIndex] & 1) {
|
|
|
953 |
px = x[pt];
|
|
|
954 |
py = y[pt];
|
|
|
955 |
if (this->ppx != px || this->ppy != py) {
|
|
|
956 |
TransformF26Dot6PointFloat(&p1, px, py, m);
|
|
|
957 |
exp->LineTo(exp, &p1);
|
|
|
958 |
this->ppx = px; this->ppy = py;
|
|
|
959 |
p0 = p1;
|
|
|
960 |
}
|
|
|
961 |
}
|
|
|
962 |
} else {
|
|
|
963 |
F26Dot6 prevX, prevY, nextX, nextY;
|
|
|
964 |
|
|
|
965 |
px = x[pt];
|
|
|
966 |
py = y[pt];
|
|
|
967 |
# if AVECTOR_BUG
|
|
|
968 |
if(x[pt] < xMin || xMax < x[pt] || y[pt] < yMin || yMax < y[pt]) {
|
|
|
969 |
px=AVE(x[prevIndex], x[nextIndex]);
|
|
|
970 |
py=AVE(y[prevIndex], y[nextIndex]);
|
|
|
971 |
}
|
|
|
972 |
# endif
|
|
|
973 |
if (onCurve[prevIndex] & 1) {
|
|
|
974 |
prevX = x[prevIndex];
|
|
|
975 |
prevY = y[prevIndex];
|
|
|
976 |
} else {
|
|
|
977 |
prevX = AVE(x[prevIndex], px);
|
|
|
978 |
prevY = AVE(y[prevIndex], py);
|
|
|
979 |
}
|
|
|
980 |
if (onCurve[nextIndex] & 1) {
|
|
|
981 |
nextX = x[nextIndex];
|
|
|
982 |
nextY = y[nextIndex];
|
|
|
983 |
} else {
|
|
|
984 |
nextX = AVE(px, x[nextIndex]);
|
|
|
985 |
nextY = AVE(py, y[nextIndex]);
|
|
|
986 |
}
|
|
|
987 |
if (this->ppx != nextX || this->ppy != nextY) {
|
|
|
988 |
double dx1, dy1, dx2, dy2, dx3, dy3;
|
|
|
989 |
const double prec = 1e-6;
|
|
|
990 |
|
|
|
991 |
TransformF26Dot6PointFloat(&p1, (prevX + (px << 1)) / 3, (prevY + (py << 1)) / 3, m);
|
|
|
992 |
TransformF26Dot6PointFloat(&p2, (nextX + (px << 1)) / 3, (nextY + (py << 1)) / 3, m);
|
|
|
993 |
TransformF26Dot6PointFloat(&p3, nextX, nextY, m);
|
|
|
994 |
dx1 = p1.x - p0.x, dy1 = p1.y - p0.y;
|
|
|
995 |
dx2 = p2.x - p0.x, dy2 = p2.y - p0.y;
|
|
|
996 |
dx3 = p3.x - p0.x, dy3 = p3.y - p0.y;
|
|
|
997 |
if (fabs(dx1 * dy3 - dy1 * dx3) > prec * fabs(dx1 * dx3 - dy1 * dy3) ||
|
|
|
998 |
fabs(dx2 * dy3 - dy2 * dx3) > prec * fabs(dx2 * dx3 - dy2 * dy3))
|
|
|
999 |
exp->CurveTo(exp, &p1, &p2, &p3);
|
|
|
1000 |
else
|
|
|
1001 |
exp->LineTo(exp, &p3);
|
|
|
1002 |
this->ppx = nextX; this->ppy = nextY;
|
|
|
1003 |
p0 = p3;
|
|
|
1004 |
}
|
|
|
1005 |
}
|
|
|
1006 |
}
|
|
|
1007 |
exp->Close(exp);
|
|
|
1008 |
}
|
|
|
1009 |
x += pts;
|
|
|
1010 |
y += pts;
|
|
|
1011 |
onCurve += pts;
|
|
|
1012 |
sp = *endP++;
|
|
|
1013 |
}
|
|
|
1014 |
}
|
|
|
1015 |
|
|
|
1016 |
FontError ttfOutliner__Outline(ttfOutliner *this, int glyphIndex,
|
|
|
1017 |
float orig_x, float orig_y, FloatMatrix *m1)
|
|
|
1018 |
{ ttfFont *pFont = this->pFont;
|
|
|
1019 |
FontError error;
|
|
|
1020 |
|
|
|
1021 |
this->post_transform = *m1;
|
|
|
1022 |
this->out.contourCount = 0;
|
|
|
1023 |
this->out.pointCount = 0;
|
|
|
1024 |
this->out.bCompound = FALSE;
|
|
|
1025 |
this->nPointsTotal = 0;
|
|
|
1026 |
this->nContoursTotal = 0;
|
|
|
1027 |
this->out.advance.x = this->out.advance.y = 0;
|
|
|
1028 |
ttfFont__StartGlyph(pFont);
|
|
|
1029 |
error = ttfOutliner__BuildGlyphOutline(this, glyphIndex, orig_x, orig_y, &this->out);
|
|
|
1030 |
ttfFont__StopGlyph(pFont);
|
|
|
1031 |
if (pFont->nUnitsPerEm <= 0)
|
|
|
1032 |
pFont->nUnitsPerEm = 1024;
|
|
|
1033 |
if (pFont->design_grid) {
|
|
|
1034 |
this->post_transform.a /= pFont->nUnitsPerEm;
|
|
|
1035 |
this->post_transform.b /= pFont->nUnitsPerEm;
|
|
|
1036 |
this->post_transform.c /= pFont->nUnitsPerEm;
|
|
|
1037 |
this->post_transform.d /= pFont->nUnitsPerEm;
|
|
|
1038 |
}
|
|
|
1039 |
if (error != fNoError && error != fPatented)
|
|
|
1040 |
return error;
|
|
|
1041 |
return error;
|
|
|
1042 |
}
|