summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/freetype/src
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/3rdparty/freetype/src
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/3rdparty/freetype/src')
-rw-r--r--src/3rdparty/freetype/src/Jamfile25
-rw-r--r--src/3rdparty/freetype/src/autofit/Jamfile39
-rw-r--r--src/3rdparty/freetype/src/autofit/afangles.c292
-rw-r--r--src/3rdparty/freetype/src/autofit/afangles.h7
-rw-r--r--src/3rdparty/freetype/src/autofit/afcjk.c1513
-rw-r--r--src/3rdparty/freetype/src/autofit/afcjk.h58
-rw-r--r--src/3rdparty/freetype/src/autofit/afdummy.c62
-rw-r--r--src/3rdparty/freetype/src/autofit/afdummy.h43
-rw-r--r--src/3rdparty/freetype/src/autofit/aferrors.h40
-rw-r--r--src/3rdparty/freetype/src/autofit/afglobal.c289
-rw-r--r--src/3rdparty/freetype/src/autofit/afglobal.h67
-rw-r--r--src/3rdparty/freetype/src/autofit/afhints.c1264
-rw-r--r--src/3rdparty/freetype/src/autofit/afhints.h333
-rw-r--r--src/3rdparty/freetype/src/autofit/afindic.c134
-rw-r--r--src/3rdparty/freetype/src/autofit/afindic.h41
-rw-r--r--src/3rdparty/freetype/src/autofit/aflatin.c2177
-rw-r--r--src/3rdparty/freetype/src/autofit/aflatin.h209
-rw-r--r--src/3rdparty/freetype/src/autofit/aflatin2.c2292
-rw-r--r--src/3rdparty/freetype/src/autofit/aflatin2.h40
-rw-r--r--src/3rdparty/freetype/src/autofit/afloader.c535
-rw-r--r--src/3rdparty/freetype/src/autofit/afloader.h73
-rw-r--r--src/3rdparty/freetype/src/autofit/afmodule.c97
-rw-r--r--src/3rdparty/freetype/src/autofit/afmodule.h37
-rw-r--r--src/3rdparty/freetype/src/autofit/aftypes.h350
-rw-r--r--src/3rdparty/freetype/src/autofit/afwarp.c338
-rw-r--r--src/3rdparty/freetype/src/autofit/afwarp.h64
-rw-r--r--src/3rdparty/freetype/src/autofit/autofit.c40
-rw-r--r--src/3rdparty/freetype/src/autofit/module.mk23
-rw-r--r--src/3rdparty/freetype/src/autofit/rules.mk78
-rw-r--r--src/3rdparty/freetype/src/base/Jamfile59
-rw-r--r--src/3rdparty/freetype/src/base/ftadvanc.c163
-rw-r--r--src/3rdparty/freetype/src/base/ftapi.c121
-rw-r--r--src/3rdparty/freetype/src/base/ftbase.c39
-rw-r--r--src/3rdparty/freetype/src/base/ftbase.h57
-rw-r--r--src/3rdparty/freetype/src/base/ftbbox.c659
-rw-r--r--src/3rdparty/freetype/src/base/ftbdf.c88
-rw-r--r--src/3rdparty/freetype/src/base/ftbitmap.c659
-rw-r--r--src/3rdparty/freetype/src/base/ftcalc.c953
-rw-r--r--src/3rdparty/freetype/src/base/ftcid.c117
-rw-r--r--src/3rdparty/freetype/src/base/ftdbgmem.c997
-rw-r--r--src/3rdparty/freetype/src/base/ftdebug.c246
-rw-r--r--src/3rdparty/freetype/src/base/ftfstype.c62
-rw-r--r--src/3rdparty/freetype/src/base/ftgasp.c61
-rw-r--r--src/3rdparty/freetype/src/base/ftgloadr.c394
-rw-r--r--src/3rdparty/freetype/src/base/ftglyph.c626
-rw-r--r--src/3rdparty/freetype/src/base/ftgxval.c129
-rw-r--r--src/3rdparty/freetype/src/base/ftinit.c163
-rw-r--r--src/3rdparty/freetype/src/base/ftlcdfil.c351
-rw-r--r--src/3rdparty/freetype/src/base/ftmac.c1057
-rw-r--r--src/3rdparty/freetype/src/base/ftmm.c202
-rw-r--r--src/3rdparty/freetype/src/base/ftnames.c94
-rw-r--r--src/3rdparty/freetype/src/base/ftobjs.c4402
-rw-r--r--src/3rdparty/freetype/src/base/ftotval.c84
-rw-r--r--src/3rdparty/freetype/src/base/ftoutln.c1128
-rw-r--r--src/3rdparty/freetype/src/base/ftpatent.c281
-rw-r--r--src/3rdparty/freetype/src/base/ftpfr.c143
-rw-r--r--src/3rdparty/freetype/src/base/ftrfork.c821
-rw-r--r--src/3rdparty/freetype/src/base/ftstream.c846
-rw-r--r--src/3rdparty/freetype/src/base/ftstroke.c2009
-rw-r--r--src/3rdparty/freetype/src/base/ftsynth.c137
-rw-r--r--src/3rdparty/freetype/src/base/ftsystem.c301
-rw-r--r--src/3rdparty/freetype/src/base/fttrigon.c546
-rw-r--r--src/3rdparty/freetype/src/base/fttype1.c94
-rw-r--r--src/3rdparty/freetype/src/base/ftutil.c501
-rw-r--r--src/3rdparty/freetype/src/base/ftwinfnt.c51
-rw-r--r--src/3rdparty/freetype/src/base/ftxf86.c40
-rw-r--r--src/3rdparty/freetype/src/base/rules.mk96
-rw-r--r--src/3rdparty/freetype/src/bdf/Jamfile29
-rw-r--r--src/3rdparty/freetype/src/bdf/README148
-rw-r--r--src/3rdparty/freetype/src/bdf/bdf.c34
-rw-r--r--src/3rdparty/freetype/src/bdf/bdf.h295
-rw-r--r--src/3rdparty/freetype/src/bdf/bdfdrivr.c855
-rw-r--r--src/3rdparty/freetype/src/bdf/bdfdrivr.h76
-rw-r--r--src/3rdparty/freetype/src/bdf/bdferror.h44
-rw-r--r--src/3rdparty/freetype/src/bdf/bdflib.c2479
-rw-r--r--src/3rdparty/freetype/src/bdf/module.mk34
-rw-r--r--src/3rdparty/freetype/src/bdf/rules.mk81
-rw-r--r--src/3rdparty/freetype/src/cache/Jamfile43
-rw-r--r--src/3rdparty/freetype/src/cache/ftcache.c31
-rw-r--r--src/3rdparty/freetype/src/cache/ftcbasic.c811
-rw-r--r--src/3rdparty/freetype/src/cache/ftccache.c592
-rw-r--r--src/3rdparty/freetype/src/cache/ftccache.h317
-rw-r--r--src/3rdparty/freetype/src/cache/ftccback.h90
-rw-r--r--src/3rdparty/freetype/src/cache/ftccmap.c425
-rw-r--r--src/3rdparty/freetype/src/cache/ftcerror.h40
-rw-r--r--src/3rdparty/freetype/src/cache/ftcglyph.c211
-rw-r--r--src/3rdparty/freetype/src/cache/ftcglyph.h322
-rw-r--r--src/3rdparty/freetype/src/cache/ftcimage.c163
-rw-r--r--src/3rdparty/freetype/src/cache/ftcimage.h107
-rw-r--r--src/3rdparty/freetype/src/cache/ftcmanag.c733
-rw-r--r--src/3rdparty/freetype/src/cache/ftcmanag.h175
-rw-r--r--src/3rdparty/freetype/src/cache/ftcmru.c357
-rw-r--r--src/3rdparty/freetype/src/cache/ftcmru.h247
-rw-r--r--src/3rdparty/freetype/src/cache/ftcsbits.c401
-rw-r--r--src/3rdparty/freetype/src/cache/ftcsbits.h98
-rw-r--r--src/3rdparty/freetype/src/cache/rules.mk80
-rw-r--r--src/3rdparty/freetype/src/cff/Jamfile29
-rw-r--r--src/3rdparty/freetype/src/cff/cff.c29
-rw-r--r--src/3rdparty/freetype/src/cff/cffcmap.c224
-rw-r--r--src/3rdparty/freetype/src/cff/cffcmap.h69
-rw-r--r--src/3rdparty/freetype/src/cff/cffdrivr.c682
-rw-r--r--src/3rdparty/freetype/src/cff/cffdrivr.h39
-rw-r--r--src/3rdparty/freetype/src/cff/cfferrs.h41
-rw-r--r--src/3rdparty/freetype/src/cff/cffgload.c2818
-rw-r--r--src/3rdparty/freetype/src/cff/cffgload.h203
-rw-r--r--src/3rdparty/freetype/src/cff/cffload.c1604
-rw-r--r--src/3rdparty/freetype/src/cff/cffload.h80
-rw-r--r--src/3rdparty/freetype/src/cff/cffobjs.c965
-rw-r--r--src/3rdparty/freetype/src/cff/cffobjs.h181
-rw-r--r--src/3rdparty/freetype/src/cff/cffparse.c848
-rw-r--r--src/3rdparty/freetype/src/cff/cffparse.h69
-rw-r--r--src/3rdparty/freetype/src/cff/cfftoken.h97
-rw-r--r--src/3rdparty/freetype/src/cff/cfftypes.h274
-rw-r--r--src/3rdparty/freetype/src/cff/module.mk23
-rw-r--r--src/3rdparty/freetype/src/cff/rules.mk72
-rw-r--r--src/3rdparty/freetype/src/cid/Jamfile29
-rw-r--r--src/3rdparty/freetype/src/cid/ciderrs.h40
-rw-r--r--src/3rdparty/freetype/src/cid/cidgload.c433
-rw-r--r--src/3rdparty/freetype/src/cid/cidgload.h51
-rw-r--r--src/3rdparty/freetype/src/cid/cidload.c672
-rw-r--r--src/3rdparty/freetype/src/cid/cidload.h53
-rw-r--r--src/3rdparty/freetype/src/cid/cidobjs.c481
-rw-r--r--src/3rdparty/freetype/src/cid/cidobjs.h154
-rw-r--r--src/3rdparty/freetype/src/cid/cidparse.c226
-rw-r--r--src/3rdparty/freetype/src/cid/cidparse.h123
-rw-r--r--src/3rdparty/freetype/src/cid/cidriver.c241
-rw-r--r--src/3rdparty/freetype/src/cid/cidriver.h39
-rw-r--r--src/3rdparty/freetype/src/cid/cidtoken.h112
-rw-r--r--src/3rdparty/freetype/src/cid/module.mk23
-rw-r--r--src/3rdparty/freetype/src/cid/rules.mk70
-rw-r--r--src/3rdparty/freetype/src/cid/type1cid.c29
-rw-r--r--src/3rdparty/freetype/src/gxvalid/Jamfile33
-rw-r--r--src/3rdparty/freetype/src/gxvalid/README532
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvalid.c46
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvalid.h107
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvbsln.c333
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvcommn.c1758
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvcommn.h560
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxverror.h51
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvfeat.c344
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvfeat.h172
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvfgen.c482
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvjust.c630
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvkern.c876
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvlcar.c223
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvmod.c285
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvmod.h46
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvmort.c285
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvmort.h93
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvmort0.c137
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvmort1.c258
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvmort2.c282
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvmort4.c125
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvmort5.c226
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvmorx.c184
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvmorx.h67
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvmorx0.c103
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvmorx1.c274
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvmorx2.c285
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvmorx4.c55
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvmorx5.c217
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvopbd.c217
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvprop.c301
-rw-r--r--src/3rdparty/freetype/src/gxvalid/gxvtrak.c277
-rw-r--r--src/3rdparty/freetype/src/gxvalid/module.mk23
-rw-r--r--src/3rdparty/freetype/src/gxvalid/rules.mk94
-rw-r--r--src/3rdparty/freetype/src/gzip/Jamfile16
-rw-r--r--src/3rdparty/freetype/src/gzip/adler32.c48
-rw-r--r--src/3rdparty/freetype/src/gzip/ftgzip.c682
-rw-r--r--src/3rdparty/freetype/src/gzip/infblock.c387
-rw-r--r--src/3rdparty/freetype/src/gzip/infblock.h36
-rw-r--r--src/3rdparty/freetype/src/gzip/infcodes.c250
-rw-r--r--src/3rdparty/freetype/src/gzip/infcodes.h31
-rw-r--r--src/3rdparty/freetype/src/gzip/inffixed.h151
-rw-r--r--src/3rdparty/freetype/src/gzip/inflate.c273
-rw-r--r--src/3rdparty/freetype/src/gzip/inftrees.c468
-rw-r--r--src/3rdparty/freetype/src/gzip/inftrees.h63
-rw-r--r--src/3rdparty/freetype/src/gzip/infutil.c86
-rw-r--r--src/3rdparty/freetype/src/gzip/infutil.h98
-rw-r--r--src/3rdparty/freetype/src/gzip/rules.mk75
-rw-r--r--src/3rdparty/freetype/src/gzip/zconf.h285
-rw-r--r--src/3rdparty/freetype/src/gzip/zlib.h837
-rw-r--r--src/3rdparty/freetype/src/gzip/zutil.c181
-rw-r--r--src/3rdparty/freetype/src/gzip/zutil.h215
-rw-r--r--src/3rdparty/freetype/src/lzw/Jamfile16
-rw-r--r--src/3rdparty/freetype/src/lzw/ftlzw.c412
-rw-r--r--src/3rdparty/freetype/src/lzw/ftzopen.c398
-rw-r--r--src/3rdparty/freetype/src/lzw/ftzopen.h171
-rw-r--r--src/3rdparty/freetype/src/lzw/rules.mk70
-rw-r--r--src/3rdparty/freetype/src/otvalid/Jamfile29
-rw-r--r--src/3rdparty/freetype/src/otvalid/module.mk23
-rw-r--r--src/3rdparty/freetype/src/otvalid/otvalid.c31
-rw-r--r--src/3rdparty/freetype/src/otvalid/otvalid.h78
-rw-r--r--src/3rdparty/freetype/src/otvalid/otvbase.c318
-rw-r--r--src/3rdparty/freetype/src/otvalid/otvcommn.c1086
-rw-r--r--src/3rdparty/freetype/src/otvalid/otvcommn.h437
-rw-r--r--src/3rdparty/freetype/src/otvalid/otverror.h43
-rw-r--r--src/3rdparty/freetype/src/otvalid/otvgdef.c224
-rw-r--r--src/3rdparty/freetype/src/otvalid/otvgpos.c1016
-rw-r--r--src/3rdparty/freetype/src/otvalid/otvgpos.h36
-rw-r--r--src/3rdparty/freetype/src/otvalid/otvgsub.c584
-rw-r--r--src/3rdparty/freetype/src/otvalid/otvjstf.c258
-rw-r--r--src/3rdparty/freetype/src/otvalid/otvmath.c452
-rw-r--r--src/3rdparty/freetype/src/otvalid/otvmod.c267
-rw-r--r--src/3rdparty/freetype/src/otvalid/otvmod.h39
-rw-r--r--src/3rdparty/freetype/src/otvalid/rules.mk78
-rw-r--r--src/3rdparty/freetype/src/pcf/Jamfile29
-rw-r--r--src/3rdparty/freetype/src/pcf/README114
-rw-r--r--src/3rdparty/freetype/src/pcf/module.mk34
-rw-r--r--src/3rdparty/freetype/src/pcf/pcf.c36
-rw-r--r--src/3rdparty/freetype/src/pcf/pcf.h237
-rw-r--r--src/3rdparty/freetype/src/pcf/pcfdrivr.c681
-rw-r--r--src/3rdparty/freetype/src/pcf/pcfdrivr.h44
-rw-r--r--src/3rdparty/freetype/src/pcf/pcferror.h40
-rw-r--r--src/3rdparty/freetype/src/pcf/pcfread.c1271
-rw-r--r--src/3rdparty/freetype/src/pcf/pcfread.h45
-rw-r--r--src/3rdparty/freetype/src/pcf/pcfutil.c104
-rw-r--r--src/3rdparty/freetype/src/pcf/pcfutil.h55
-rw-r--r--src/3rdparty/freetype/src/pcf/rules.mk79
-rw-r--r--src/3rdparty/freetype/src/pfr/Jamfile29
-rw-r--r--src/3rdparty/freetype/src/pfr/module.mk23
-rw-r--r--src/3rdparty/freetype/src/pfr/pfr.c29
-rw-r--r--src/3rdparty/freetype/src/pfr/pfrcmap.c167
-rw-r--r--src/3rdparty/freetype/src/pfr/pfrcmap.h46
-rw-r--r--src/3rdparty/freetype/src/pfr/pfrdrivr.c214
-rw-r--r--src/3rdparty/freetype/src/pfr/pfrdrivr.h39
-rw-r--r--src/3rdparty/freetype/src/pfr/pfrerror.h40
-rw-r--r--src/3rdparty/freetype/src/pfr/pfrgload.c828
-rw-r--r--src/3rdparty/freetype/src/pfr/pfrgload.h49
-rw-r--r--src/3rdparty/freetype/src/pfr/pfrload.c938
-rw-r--r--src/3rdparty/freetype/src/pfr/pfrload.h118
-rw-r--r--src/3rdparty/freetype/src/pfr/pfrobjs.c581
-rw-r--r--src/3rdparty/freetype/src/pfr/pfrobjs.h96
-rw-r--r--src/3rdparty/freetype/src/pfr/pfrsbit.c680
-rw-r--r--src/3rdparty/freetype/src/pfr/pfrsbit.h36
-rw-r--r--src/3rdparty/freetype/src/pfr/pfrtypes.h362
-rw-r--r--src/3rdparty/freetype/src/pfr/rules.mk73
-rw-r--r--src/3rdparty/freetype/src/psaux/Jamfile31
-rw-r--r--src/3rdparty/freetype/src/psaux/afmparse.c965
-rw-r--r--src/3rdparty/freetype/src/psaux/afmparse.h87
-rw-r--r--src/3rdparty/freetype/src/psaux/module.mk23
-rw-r--r--src/3rdparty/freetype/src/psaux/psaux.c34
-rw-r--r--src/3rdparty/freetype/src/psaux/psauxerr.h41
-rw-r--r--src/3rdparty/freetype/src/psaux/psauxmod.c139
-rw-r--r--src/3rdparty/freetype/src/psaux/psauxmod.h38
-rw-r--r--src/3rdparty/freetype/src/psaux/psconv.c474
-rw-r--r--src/3rdparty/freetype/src/psaux/psconv.h71
-rw-r--r--src/3rdparty/freetype/src/psaux/psobjs.c1706
-rw-r--r--src/3rdparty/freetype/src/psaux/psobjs.h212
-rw-r--r--src/3rdparty/freetype/src/psaux/rules.mk73
-rw-r--r--src/3rdparty/freetype/src/psaux/t1cmap.c341
-rw-r--r--src/3rdparty/freetype/src/psaux/t1cmap.h105
-rw-r--r--src/3rdparty/freetype/src/psaux/t1decode.c1474
-rw-r--r--src/3rdparty/freetype/src/psaux/t1decode.h64
-rw-r--r--src/3rdparty/freetype/src/pshinter/Jamfile29
-rw-r--r--src/3rdparty/freetype/src/pshinter/module.mk23
-rw-r--r--src/3rdparty/freetype/src/pshinter/pshalgo.c2302
-rw-r--r--src/3rdparty/freetype/src/pshinter/pshalgo.h255
-rw-r--r--src/3rdparty/freetype/src/pshinter/pshglob.c750
-rw-r--r--src/3rdparty/freetype/src/pshinter/pshglob.h196
-rw-r--r--src/3rdparty/freetype/src/pshinter/pshinter.c28
-rw-r--r--src/3rdparty/freetype/src/pshinter/pshmod.c121
-rw-r--r--src/3rdparty/freetype/src/pshinter/pshmod.h39
-rw-r--r--src/3rdparty/freetype/src/pshinter/pshnterr.h40
-rw-r--r--src/3rdparty/freetype/src/pshinter/pshrec.c1215
-rw-r--r--src/3rdparty/freetype/src/pshinter/pshrec.h176
-rw-r--r--src/3rdparty/freetype/src/pshinter/rules.mk72
-rw-r--r--src/3rdparty/freetype/src/psnames/Jamfile29
-rw-r--r--src/3rdparty/freetype/src/psnames/module.mk23
-rw-r--r--src/3rdparty/freetype/src/psnames/psmodule.c590
-rw-r--r--src/3rdparty/freetype/src/psnames/psmodule.h38
-rw-r--r--src/3rdparty/freetype/src/psnames/psnamerr.h41
-rw-r--r--src/3rdparty/freetype/src/psnames/psnames.c25
-rw-r--r--src/3rdparty/freetype/src/psnames/pstables.h4095
-rw-r--r--src/3rdparty/freetype/src/psnames/rules.mk70
-rw-r--r--src/3rdparty/freetype/src/raster/Jamfile29
-rw-r--r--src/3rdparty/freetype/src/raster/ftmisc.h84
-rw-r--r--src/3rdparty/freetype/src/raster/ftraster.c3433
-rw-r--r--src/3rdparty/freetype/src/raster/ftraster.h46
-rw-r--r--src/3rdparty/freetype/src/raster/ftrend1.c273
-rw-r--r--src/3rdparty/freetype/src/raster/ftrend1.h44
-rw-r--r--src/3rdparty/freetype/src/raster/module.mk23
-rw-r--r--src/3rdparty/freetype/src/raster/raster.c26
-rw-r--r--src/3rdparty/freetype/src/raster/rasterrs.h41
-rw-r--r--src/3rdparty/freetype/src/raster/rules.mk70
-rw-r--r--src/3rdparty/freetype/src/sfnt/Jamfile29
-rw-r--r--src/3rdparty/freetype/src/sfnt/module.mk23
-rw-r--r--src/3rdparty/freetype/src/sfnt/rules.mk79
-rw-r--r--src/3rdparty/freetype/src/sfnt/sfdriver.c643
-rw-r--r--src/3rdparty/freetype/src/sfnt/sfdriver.h38
-rw-r--r--src/3rdparty/freetype/src/sfnt/sferrors.h41
-rw-r--r--src/3rdparty/freetype/src/sfnt/sfnt.c41
-rw-r--r--src/3rdparty/freetype/src/sfnt/sfobjs.c1130
-rw-r--r--src/3rdparty/freetype/src/sfnt/sfobjs.h54
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttbdf.c250
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttbdf.h46
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttcmap.c3187
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttcmap.h85
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttkern.c305
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttkern.h52
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttload.c1248
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttload.h112
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttmtx.c466
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttmtx.h55
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttpost.c522
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttpost.h46
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttsbit.c1507
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttsbit.h79
-rw-r--r--src/3rdparty/freetype/src/sfnt/ttsbit0.c969
-rw-r--r--src/3rdparty/freetype/src/smooth/Jamfile29
-rw-r--r--src/3rdparty/freetype/src/smooth/ftgrays.c2057
-rw-r--r--src/3rdparty/freetype/src/smooth/ftgrays.h57
-rw-r--r--src/3rdparty/freetype/src/smooth/ftsmerrs.h41
-rw-r--r--src/3rdparty/freetype/src/smooth/ftsmooth.c467
-rw-r--r--src/3rdparty/freetype/src/smooth/ftsmooth.h49
-rw-r--r--src/3rdparty/freetype/src/smooth/module.mk27
-rw-r--r--src/3rdparty/freetype/src/smooth/rules.mk69
-rw-r--r--src/3rdparty/freetype/src/smooth/smooth.c26
-rw-r--r--src/3rdparty/freetype/src/tools/Jamfile5
-rw-r--r--src/3rdparty/freetype/src/tools/apinames.c443
-rw-r--r--src/3rdparty/freetype/src/tools/cordic.py79
-rw-r--r--src/3rdparty/freetype/src/tools/docmaker/content.py584
-rw-r--r--src/3rdparty/freetype/src/tools/docmaker/docbeauty.py113
-rw-r--r--src/3rdparty/freetype/src/tools/docmaker/docmaker.py106
-rw-r--r--src/3rdparty/freetype/src/tools/docmaker/formatter.py188
-rw-r--r--src/3rdparty/freetype/src/tools/docmaker/sources.py347
-rw-r--r--src/3rdparty/freetype/src/tools/docmaker/tohtml.py593
-rw-r--r--src/3rdparty/freetype/src/tools/docmaker/utils.py132
-rw-r--r--src/3rdparty/freetype/src/tools/ftrandom/Makefile35
-rw-r--r--src/3rdparty/freetype/src/tools/ftrandom/README48
-rw-r--r--src/3rdparty/freetype/src/tools/ftrandom/ftrandom.c659
-rw-r--r--src/3rdparty/freetype/src/tools/glnames.py5287
-rw-r--r--src/3rdparty/freetype/src/tools/test_afm.c157
-rw-r--r--src/3rdparty/freetype/src/tools/test_bbox.c160
-rw-r--r--src/3rdparty/freetype/src/tools/test_trig.c236
-rw-r--r--src/3rdparty/freetype/src/truetype/Jamfile29
-rw-r--r--src/3rdparty/freetype/src/truetype/module.mk23
-rw-r--r--src/3rdparty/freetype/src/truetype/rules.mk72
-rw-r--r--src/3rdparty/freetype/src/truetype/truetype.c36
-rw-r--r--src/3rdparty/freetype/src/truetype/ttdriver.c474
-rw-r--r--src/3rdparty/freetype/src/truetype/ttdriver.h38
-rw-r--r--src/3rdparty/freetype/src/truetype/tterrors.h40
-rw-r--r--src/3rdparty/freetype/src/truetype/ttgload.c2022
-rw-r--r--src/3rdparty/freetype/src/truetype/ttgload.h63
-rw-r--r--src/3rdparty/freetype/src/truetype/ttgxvar.c1541
-rw-r--r--src/3rdparty/freetype/src/truetype/ttgxvar.h182
-rw-r--r--src/3rdparty/freetype/src/truetype/ttinterp.c7828
-rw-r--r--src/3rdparty/freetype/src/truetype/ttinterp.h311
-rw-r--r--src/3rdparty/freetype/src/truetype/ttobjs.c955
-rw-r--r--src/3rdparty/freetype/src/truetype/ttobjs.h463
-rw-r--r--src/3rdparty/freetype/src/truetype/ttpload.c574
-rw-r--r--src/3rdparty/freetype/src/truetype/ttpload.h75
-rw-r--r--src/3rdparty/freetype/src/type1/Jamfile29
-rw-r--r--src/3rdparty/freetype/src/type1/module.mk23
-rw-r--r--src/3rdparty/freetype/src/type1/rules.mk73
-rw-r--r--src/3rdparty/freetype/src/type1/t1afm.c390
-rw-r--r--src/3rdparty/freetype/src/type1/t1afm.h54
-rw-r--r--src/3rdparty/freetype/src/type1/t1driver.c331
-rw-r--r--src/3rdparty/freetype/src/type1/t1driver.h38
-rw-r--r--src/3rdparty/freetype/src/type1/t1errors.h40
-rw-r--r--src/3rdparty/freetype/src/type1/t1gload.c489
-rw-r--r--src/3rdparty/freetype/src/type1/t1gload.h53
-rw-r--r--src/3rdparty/freetype/src/type1/t1load.c2245
-rw-r--r--src/3rdparty/freetype/src/type1/t1load.h102
-rw-r--r--src/3rdparty/freetype/src/type1/t1objs.c592
-rw-r--r--src/3rdparty/freetype/src/type1/t1objs.h171
-rw-r--r--src/3rdparty/freetype/src/type1/t1parse.c484
-rw-r--r--src/3rdparty/freetype/src/type1/t1parse.h135
-rw-r--r--src/3rdparty/freetype/src/type1/t1tokens.h143
-rw-r--r--src/3rdparty/freetype/src/type1/type1.c33
-rw-r--r--src/3rdparty/freetype/src/type42/Jamfile29
-rw-r--r--src/3rdparty/freetype/src/type42/module.mk23
-rw-r--r--src/3rdparty/freetype/src/type42/rules.mk70
-rw-r--r--src/3rdparty/freetype/src/type42/t42drivr.c246
-rw-r--r--src/3rdparty/freetype/src/type42/t42drivr.h38
-rw-r--r--src/3rdparty/freetype/src/type42/t42error.h40
-rw-r--r--src/3rdparty/freetype/src/type42/t42objs.c647
-rw-r--r--src/3rdparty/freetype/src/type42/t42objs.h124
-rw-r--r--src/3rdparty/freetype/src/type42/t42parse.c1175
-rw-r--r--src/3rdparty/freetype/src/type42/t42parse.h90
-rw-r--r--src/3rdparty/freetype/src/type42/t42types.h56
-rw-r--r--src/3rdparty/freetype/src/type42/type42.c25
-rw-r--r--src/3rdparty/freetype/src/winfonts/Jamfile16
-rw-r--r--src/3rdparty/freetype/src/winfonts/fnterrs.h41
-rw-r--r--src/3rdparty/freetype/src/winfonts/module.mk23
-rw-r--r--src/3rdparty/freetype/src/winfonts/rules.mk65
-rw-r--r--src/3rdparty/freetype/src/winfonts/winfnt.c1135
-rw-r--r--src/3rdparty/freetype/src/winfonts/winfnt.h167
388 files changed, 144390 insertions, 0 deletions
diff --git a/src/3rdparty/freetype/src/Jamfile b/src/3rdparty/freetype/src/Jamfile
new file mode 100644
index 0000000000..76ee0f46e6
--- /dev/null
+++ b/src/3rdparty/freetype/src/Jamfile
@@ -0,0 +1,25 @@
+# FreeType 2 src Jamfile
+#
+# Copyright 2001, 2002 by
+# David Turner, Robert Wilhelm, and Werner Lemberg.
+#
+# This file is part of the FreeType project, and may only be used, modified,
+# and distributed under the terms of the FreeType project license,
+# LICENSE.TXT. By continuing to use, modify, or distribute this file you
+# indicate that you have read the license and understand and accept it
+# fully.
+
+SubDir FT2_TOP $(FT2_SRC_DIR) ;
+
+# The file <freetype/internal/internal.h> is used to define macros that are
+# later used in #include statements. It needs to be parsed in order to
+# record these definitions.
+#
+HDRMACRO [ FT2_SubDir $(FT2_INCLUDE_DIR) internal internal.h ] ;
+
+for xx in $(FT2_COMPONENTS)
+{
+ SubInclude FT2_TOP $(FT2_SRC_DIR) $(xx) ;
+}
+
+# end of src Jamfile
diff --git a/src/3rdparty/freetype/src/autofit/Jamfile b/src/3rdparty/freetype/src/autofit/Jamfile
new file mode 100644
index 0000000000..acee8bf2cb
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/Jamfile
@@ -0,0 +1,39 @@
+# FreeType 2 src/autofit Jamfile
+#
+# Copyright 2003, 2004, 2005, 2006, 2007 by
+# David Turner, Robert Wilhelm, and Werner Lemberg.
+#
+# This file is part of the FreeType project, and may only be used, modified,
+# and distributed under the terms of the FreeType project license,
+# LICENSE.TXT. By continuing to use, modify, or distribute this file you
+# indicate that you have read the license and understand and accept it
+# fully.
+
+SubDir FT2_TOP src autofit ;
+
+{
+ local _sources ;
+
+ # define FT2_AUTOFIT2 do enable to experimental latin hinter replacement
+ if $(FT2_AUTOFIT2)
+ {
+ DEFINES += FT_OPTION_AUTOFIT2 ;
+ }
+ if $(FT2_MULTI)
+ {
+ _sources = afangles afglobal afhints aflatin afcjk afindic afloader afmodule afdummy afwarp ;
+
+ if $(FT2_AUTOFIT2)
+ {
+ _sources += aflatin2 ;
+ }
+ }
+ else
+ {
+ _sources = autofit ;
+ }
+
+ Library $(FT2_LIB) : $(_sources).c ;
+}
+
+# end of src/autofit Jamfile
diff --git a/src/3rdparty/freetype/src/autofit/afangles.c b/src/3rdparty/freetype/src/autofit/afangles.c
new file mode 100644
index 0000000000..e2360d157d
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/afangles.c
@@ -0,0 +1,292 @@
+/***************************************************************************/
+/* */
+/* afangles.c */
+/* */
+/* Routines used to compute vector angles with limited accuracy */
+/* and very high speed. It also contains sorting routines (body). */
+/* */
+/* Copyright 2003, 2004, 2005, 2006 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "aftypes.h"
+
+
+#if 0
+
+ FT_LOCAL_DEF( FT_Int )
+ af_corner_is_flat( FT_Pos x_in,
+ FT_Pos y_in,
+ FT_Pos x_out,
+ FT_Pos y_out )
+ {
+ FT_Pos ax = x_in;
+ FT_Pos ay = y_in;
+
+ FT_Pos d_in, d_out, d_corner;
+
+
+ if ( ax < 0 )
+ ax = -ax;
+ if ( ay < 0 )
+ ay = -ay;
+ d_in = ax + ay;
+
+ ax = x_out;
+ if ( ax < 0 )
+ ax = -ax;
+ ay = y_out;
+ if ( ay < 0 )
+ ay = -ay;
+ d_out = ax + ay;
+
+ ax = x_out + x_in;
+ if ( ax < 0 )
+ ax = -ax;
+ ay = y_out + y_in;
+ if ( ay < 0 )
+ ay = -ay;
+ d_corner = ax + ay;
+
+ return ( d_in + d_out - d_corner ) < ( d_corner >> 4 );
+ }
+
+
+ FT_LOCAL_DEF( FT_Int )
+ af_corner_orientation( FT_Pos x_in,
+ FT_Pos y_in,
+ FT_Pos x_out,
+ FT_Pos y_out )
+ {
+ FT_Pos delta;
+
+
+ delta = x_in * y_out - y_in * x_out;
+
+ if ( delta == 0 )
+ return 0;
+ else
+ return 1 - 2 * ( delta < 0 );
+ }
+
+#endif
+
+
+ /*
+ * We are not using `af_angle_atan' anymore, but we keep the source
+ * code below just in case...
+ */
+
+
+#if 0
+
+
+ /*
+ * The trick here is to realize that we don't need a very accurate angle
+ * approximation. We are going to use the result of `af_angle_atan' to
+ * only compare the sign of angle differences, or check whether its
+ * magnitude is very small.
+ *
+ * The approximation
+ *
+ * dy * PI / (|dx|+|dy|)
+ *
+ * should be enough, and much faster to compute.
+ */
+ FT_LOCAL_DEF( AF_Angle )
+ af_angle_atan( FT_Fixed dx,
+ FT_Fixed dy )
+ {
+ AF_Angle angle;
+ FT_Fixed ax = dx;
+ FT_Fixed ay = dy;
+
+
+ if ( ax < 0 )
+ ax = -ax;
+ if ( ay < 0 )
+ ay = -ay;
+
+ ax += ay;
+
+ if ( ax == 0 )
+ angle = 0;
+ else
+ {
+ angle = ( AF_ANGLE_PI2 * dy ) / ( ax + ay );
+ if ( dx < 0 )
+ {
+ if ( angle >= 0 )
+ angle = AF_ANGLE_PI - angle;
+ else
+ angle = -AF_ANGLE_PI - angle;
+ }
+ }
+
+ return angle;
+ }
+
+
+#elif 0
+
+
+ /* the following table has been automatically generated with */
+ /* the `mather.py' Python script */
+
+#define AF_ATAN_BITS 8
+
+ static const FT_Byte af_arctan[1L << AF_ATAN_BITS] =
+ {
+ 0, 0, 1, 1, 1, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 5,
+ 5, 5, 6, 6, 6, 7, 7, 7,
+ 8, 8, 8, 9, 9, 9, 10, 10,
+ 10, 10, 11, 11, 11, 12, 12, 12,
+ 13, 13, 13, 14, 14, 14, 14, 15,
+ 15, 15, 16, 16, 16, 17, 17, 17,
+ 18, 18, 18, 18, 19, 19, 19, 20,
+ 20, 20, 21, 21, 21, 21, 22, 22,
+ 22, 23, 23, 23, 24, 24, 24, 24,
+ 25, 25, 25, 26, 26, 26, 26, 27,
+ 27, 27, 28, 28, 28, 28, 29, 29,
+ 29, 30, 30, 30, 30, 31, 31, 31,
+ 31, 32, 32, 32, 33, 33, 33, 33,
+ 34, 34, 34, 34, 35, 35, 35, 35,
+ 36, 36, 36, 36, 37, 37, 37, 38,
+ 38, 38, 38, 39, 39, 39, 39, 40,
+ 40, 40, 40, 41, 41, 41, 41, 42,
+ 42, 42, 42, 42, 43, 43, 43, 43,
+ 44, 44, 44, 44, 45, 45, 45, 45,
+ 46, 46, 46, 46, 46, 47, 47, 47,
+ 47, 48, 48, 48, 48, 48, 49, 49,
+ 49, 49, 50, 50, 50, 50, 50, 51,
+ 51, 51, 51, 51, 52, 52, 52, 52,
+ 52, 53, 53, 53, 53, 53, 54, 54,
+ 54, 54, 54, 55, 55, 55, 55, 55,
+ 56, 56, 56, 56, 56, 57, 57, 57,
+ 57, 57, 57, 58, 58, 58, 58, 58,
+ 59, 59, 59, 59, 59, 59, 60, 60,
+ 60, 60, 60, 61, 61, 61, 61, 61,
+ 61, 62, 62, 62, 62, 62, 62, 63,
+ 63, 63, 63, 63, 63, 64, 64, 64
+ };
+
+
+ FT_LOCAL_DEF( AF_Angle )
+ af_angle_atan( FT_Fixed dx,
+ FT_Fixed dy )
+ {
+ AF_Angle angle;
+
+
+ /* check trivial cases */
+ if ( dy == 0 )
+ {
+ angle = 0;
+ if ( dx < 0 )
+ angle = AF_ANGLE_PI;
+ return angle;
+ }
+ else if ( dx == 0 )
+ {
+ angle = AF_ANGLE_PI2;
+ if ( dy < 0 )
+ angle = -AF_ANGLE_PI2;
+ return angle;
+ }
+
+ angle = 0;
+ if ( dx < 0 )
+ {
+ dx = -dx;
+ dy = -dy;
+ angle = AF_ANGLE_PI;
+ }
+
+ if ( dy < 0 )
+ {
+ FT_Pos tmp;
+
+
+ tmp = dx;
+ dx = -dy;
+ dy = tmp;
+ angle -= AF_ANGLE_PI2;
+ }
+
+ if ( dx == 0 && dy == 0 )
+ return 0;
+
+ if ( dx == dy )
+ angle += AF_ANGLE_PI4;
+ else if ( dx > dy )
+ angle += af_arctan[FT_DivFix( dy, dx ) >> ( 16 - AF_ATAN_BITS )];
+ else
+ angle += AF_ANGLE_PI2 -
+ af_arctan[FT_DivFix( dx, dy ) >> ( 16 - AF_ATAN_BITS )];
+
+ if ( angle > AF_ANGLE_PI )
+ angle -= AF_ANGLE_2PI;
+
+ return angle;
+ }
+
+
+#endif /* 0 */
+
+
+ FT_LOCAL_DEF( void )
+ af_sort_pos( FT_UInt count,
+ FT_Pos* table )
+ {
+ FT_UInt i, j;
+ FT_Pos swap;
+
+
+ for ( i = 1; i < count; i++ )
+ {
+ for ( j = i; j > 0; j-- )
+ {
+ if ( table[j] > table[j - 1] )
+ break;
+
+ swap = table[j];
+ table[j] = table[j - 1];
+ table[j - 1] = swap;
+ }
+ }
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_sort_widths( FT_UInt count,
+ AF_Width table )
+ {
+ FT_UInt i, j;
+ AF_WidthRec swap;
+
+
+ for ( i = 1; i < count; i++ )
+ {
+ for ( j = i; j > 0; j-- )
+ {
+ if ( table[j].org > table[j - 1].org )
+ break;
+
+ swap = table[j];
+ table[j] = table[j - 1];
+ table[j - 1] = swap;
+ }
+ }
+ }
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/afangles.h b/src/3rdparty/freetype/src/autofit/afangles.h
new file mode 100644
index 0000000000..f33f9e108e
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/afangles.h
@@ -0,0 +1,7 @@
+/*
+ * afangles.h
+ *
+ * This is a dummy file, used to please the build system. It is never
+ * included by the auto-fitter sources.
+ *
+ */
diff --git a/src/3rdparty/freetype/src/autofit/afcjk.c b/src/3rdparty/freetype/src/autofit/afcjk.c
new file mode 100644
index 0000000000..de3ce11d54
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/afcjk.c
@@ -0,0 +1,1513 @@
+/***************************************************************************/
+/* */
+/* afcjk.c */
+/* */
+/* Auto-fitter hinting routines for CJK script (body). */
+/* */
+/* Copyright 2006, 2007, 2008 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*
+ * The algorithm is based on akito's autohint patch, available here:
+ *
+ * http://www.kde.gr.jp/~akito/patch/freetype2/
+ *
+ */
+
+#include "aftypes.h"
+#include "aflatin.h"
+
+
+#ifdef AF_CONFIG_OPTION_CJK
+
+#include "afcjk.h"
+#include "aferrors.h"
+
+
+#ifdef AF_USE_WARPER
+#include "afwarp.h"
+#endif
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** C J K G L O B A L M E T R I C S *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_LOCAL_DEF( FT_Error )
+ af_cjk_metrics_init( AF_LatinMetrics metrics,
+ FT_Face face )
+ {
+ FT_CharMap oldmap = face->charmap;
+
+
+ metrics->units_per_em = face->units_per_EM;
+
+ /* TODO are there blues? */
+
+ if ( FT_Select_Charmap( face, FT_ENCODING_UNICODE ) )
+ face->charmap = NULL;
+
+ /* latin's version would suffice */
+ af_latin_metrics_init_widths( metrics, face, 0x7530 );
+
+ FT_Set_Charmap( face, oldmap );
+
+ return AF_Err_Ok;
+ }
+
+
+ static void
+ af_cjk_metrics_scale_dim( AF_LatinMetrics metrics,
+ AF_Scaler scaler,
+ AF_Dimension dim )
+ {
+ AF_LatinAxis axis;
+
+
+ axis = &metrics->axis[dim];
+
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ axis->scale = scaler->x_scale;
+ axis->delta = scaler->x_delta;
+ }
+ else
+ {
+ axis->scale = scaler->y_scale;
+ axis->delta = scaler->y_delta;
+ }
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_cjk_metrics_scale( AF_LatinMetrics metrics,
+ AF_Scaler scaler )
+ {
+ metrics->root.scaler = *scaler;
+
+ af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ );
+ af_cjk_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** C J K G L Y P H A N A L Y S I S *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static FT_Error
+ af_cjk_hints_compute_segments( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_AxisHints axis = &hints->axis[dim];
+ AF_Segment segments = axis->segments;
+ AF_Segment segment_limit = segments + axis->num_segments;
+ FT_Error error;
+ AF_Segment seg;
+
+
+ error = af_latin_hints_compute_segments( hints, dim );
+ if ( error )
+ return error;
+
+ /* a segment is round if it doesn't have successive */
+ /* on-curve points. */
+ for ( seg = segments; seg < segment_limit; seg++ )
+ {
+ AF_Point pt = seg->first;
+ AF_Point last = seg->last;
+ AF_Flags f0 = (AF_Flags)(pt->flags & AF_FLAG_CONTROL);
+ AF_Flags f1;
+
+
+ seg->flags &= ~AF_EDGE_ROUND;
+
+ for ( ; pt != last; f0 = f1 )
+ {
+ pt = pt->next;
+ f1 = (AF_Flags)(pt->flags & AF_FLAG_CONTROL);
+
+ if ( !f0 && !f1 )
+ break;
+
+ if ( pt == last )
+ seg->flags |= AF_EDGE_ROUND;
+ }
+ }
+
+ return AF_Err_Ok;
+ }
+
+
+ static void
+ af_cjk_hints_link_segments( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_AxisHints axis = &hints->axis[dim];
+ AF_Segment segments = axis->segments;
+ AF_Segment segment_limit = segments + axis->num_segments;
+ AF_Direction major_dir = axis->major_dir;
+ AF_Segment seg1, seg2;
+ FT_Pos len_threshold;
+ FT_Pos dist_threshold;
+
+
+ len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 );
+
+ dist_threshold = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
+ : hints->y_scale;
+ dist_threshold = FT_DivFix( 64 * 3, dist_threshold );
+
+ /* now compare each segment to the others */
+ for ( seg1 = segments; seg1 < segment_limit; seg1++ )
+ {
+ /* the fake segments are for metrics hinting only */
+ if ( seg1->first == seg1->last )
+ continue;
+
+ if ( seg1->dir != major_dir )
+ continue;
+
+ for ( seg2 = segments; seg2 < segment_limit; seg2++ )
+ if ( seg2 != seg1 && seg1->dir + seg2->dir == 0 )
+ {
+ FT_Pos dist = seg2->pos - seg1->pos;
+
+
+ if ( dist < 0 )
+ continue;
+
+ {
+ FT_Pos min = seg1->min_coord;
+ FT_Pos max = seg1->max_coord;
+ FT_Pos len;
+
+
+ if ( min < seg2->min_coord )
+ min = seg2->min_coord;
+
+ if ( max > seg2->max_coord )
+ max = seg2->max_coord;
+
+ len = max - min;
+ if ( len >= len_threshold )
+ {
+ if ( dist * 8 < seg1->score * 9 &&
+ ( dist * 8 < seg1->score * 7 || seg1->len < len ) )
+ {
+ seg1->score = dist;
+ seg1->len = len;
+ seg1->link = seg2;
+ }
+
+ if ( dist * 8 < seg2->score * 9 &&
+ ( dist * 8 < seg2->score * 7 || seg2->len < len ) )
+ {
+ seg2->score = dist;
+ seg2->len = len;
+ seg2->link = seg1;
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * now compute the `serif' segments
+ *
+ * In Hanzi, some strokes are wider on one or both of the ends.
+ * We either identify the stems on the ends as serifs or remove
+ * the linkage, depending on the length of the stems.
+ *
+ */
+
+ {
+ AF_Segment link1, link2;
+
+
+ for ( seg1 = segments; seg1 < segment_limit; seg1++ )
+ {
+ link1 = seg1->link;
+ if ( !link1 || link1->link != seg1 || link1->pos <= seg1->pos )
+ continue;
+
+ if ( seg1->score >= dist_threshold )
+ continue;
+
+ for ( seg2 = segments; seg2 < segment_limit; seg2++ )
+ {
+ if ( seg2->pos > seg1->pos || seg1 == seg2 )
+ continue;
+
+ link2 = seg2->link;
+ if ( !link2 || link2->link != seg2 || link2->pos < link1->pos )
+ continue;
+
+ if ( seg1->pos == seg2->pos && link1->pos == link2->pos )
+ continue;
+
+ if ( seg2->score <= seg1->score || seg1->score * 4 <= seg2->score )
+ continue;
+
+ /* seg2 < seg1 < link1 < link2 */
+
+ if ( seg1->len >= seg2->len * 3 )
+ {
+ AF_Segment seg;
+
+
+ for ( seg = segments; seg < segment_limit; seg++ )
+ {
+ AF_Segment link = seg->link;
+
+
+ if ( link == seg2 )
+ {
+ seg->link = 0;
+ seg->serif = link1;
+ }
+ else if ( link == link2 )
+ {
+ seg->link = 0;
+ seg->serif = seg1;
+ }
+ }
+ }
+ else
+ {
+ seg1->link = link1->link = 0;
+
+ break;
+ }
+ }
+ }
+ }
+
+ for ( seg1 = segments; seg1 < segment_limit; seg1++ )
+ {
+ seg2 = seg1->link;
+
+ if ( seg2 )
+ {
+ seg2->num_linked++;
+ if ( seg2->link != seg1 )
+ {
+ seg1->link = 0;
+
+ if ( seg2->score < dist_threshold || seg1->score < seg2->score * 4 )
+ seg1->serif = seg2->link;
+ else
+ seg2->num_linked--;
+ }
+ }
+ }
+ }
+
+
+ static FT_Error
+ af_cjk_hints_compute_edges( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_AxisHints axis = &hints->axis[dim];
+ FT_Error error = AF_Err_Ok;
+ FT_Memory memory = hints->memory;
+ AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim];
+
+ AF_Segment segments = axis->segments;
+ AF_Segment segment_limit = segments + axis->num_segments;
+ AF_Segment seg;
+
+ FT_Fixed scale;
+ FT_Pos edge_distance_threshold;
+
+
+ axis->num_edges = 0;
+
+ scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
+ : hints->y_scale;
+
+ /*********************************************************************/
+ /* */
+ /* We begin by generating a sorted table of edges for the current */
+ /* direction. To do so, we simply scan each segment and try to find */
+ /* an edge in our table that corresponds to its position. */
+ /* */
+ /* If no edge is found, we create and insert a new edge in the */
+ /* sorted table. Otherwise, we simply add the segment to the edge's */
+ /* list which is then processed in the second step to compute the */
+ /* edge's properties. */
+ /* */
+ /* Note that the edges table is sorted along the segment/edge */
+ /* position. */
+ /* */
+ /*********************************************************************/
+
+ edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
+ scale );
+ if ( edge_distance_threshold > 64 / 4 )
+ edge_distance_threshold = FT_DivFix( 64 / 4, scale );
+ else
+ edge_distance_threshold = laxis->edge_distance_threshold;
+
+ for ( seg = segments; seg < segment_limit; seg++ )
+ {
+ AF_Edge found = 0;
+ FT_Pos best = 0xFFFFU;
+ FT_Int ee;
+
+
+ /* look for an edge corresponding to the segment */
+ for ( ee = 0; ee < axis->num_edges; ee++ )
+ {
+ AF_Edge edge = axis->edges + ee;
+ FT_Pos dist;
+
+
+ if ( edge->dir != seg->dir )
+ continue;
+
+ dist = seg->pos - edge->fpos;
+ if ( dist < 0 )
+ dist = -dist;
+
+ if ( dist < edge_distance_threshold && dist < best )
+ {
+ AF_Segment link = seg->link;
+
+
+ /* check whether all linked segments of the candidate edge */
+ /* can make a single edge. */
+ if ( link )
+ {
+ AF_Segment seg1 = edge->first;
+ AF_Segment link1;
+ FT_Pos dist2 = 0;
+
+
+ do
+ {
+ link1 = seg1->link;
+ if ( link1 )
+ {
+ dist2 = AF_SEGMENT_DIST( link, link1 );
+ if ( dist2 >= edge_distance_threshold )
+ break;
+ }
+
+ } while ( ( seg1 = seg1->edge_next ) != edge->first );
+
+ if ( dist2 >= edge_distance_threshold )
+ continue;
+ }
+
+ best = dist;
+ found = edge;
+ }
+ }
+
+ if ( !found )
+ {
+ AF_Edge edge;
+
+
+ /* insert a new edge in the list and */
+ /* sort according to the position */
+ error = af_axis_hints_new_edge( axis, seg->pos,
+ (AF_Direction)seg->dir,
+ memory, &edge );
+ if ( error )
+ goto Exit;
+
+ /* add the segment to the new edge's list */
+ FT_ZERO( edge );
+
+ edge->first = seg;
+ edge->last = seg;
+ edge->fpos = seg->pos;
+ edge->opos = edge->pos = FT_MulFix( seg->pos, scale );
+ seg->edge_next = seg;
+ edge->dir = seg->dir;
+ }
+ else
+ {
+ /* if an edge was found, simply add the segment to the edge's */
+ /* list */
+ seg->edge_next = found->first;
+ found->last->edge_next = seg;
+ found->last = seg;
+ }
+ }
+
+ /*********************************************************************/
+ /* */
+ /* Good, we now compute each edge's properties according to segments */
+ /* found on its position. Basically, these are as follows. */
+ /* */
+ /* - edge's main direction */
+ /* - stem edge, serif edge or both (which defaults to stem then) */
+ /* - rounded edge, straight or both (which defaults to straight) */
+ /* - link for edge */
+ /* */
+ /*********************************************************************/
+
+ /* first of all, set the `edge' field in each segment -- this is */
+ /* required in order to compute edge links */
+ /* */
+ /* Note that removing this loop and setting the `edge' field of each */
+ /* segment directly in the code above slows down execution speed for */
+ /* some reasons on platforms like the Sun. */
+
+ {
+ AF_Edge edges = axis->edges;
+ AF_Edge edge_limit = edges + axis->num_edges;
+ AF_Edge edge;
+
+
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ seg = edge->first;
+ if ( seg )
+ do
+ {
+ seg->edge = edge;
+ seg = seg->edge_next;
+
+ } while ( seg != edge->first );
+ }
+
+ /* now compute each edge properties */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ FT_Int is_round = 0; /* does it contain round segments? */
+ FT_Int is_straight = 0; /* does it contain straight segments? */
+
+
+ seg = edge->first;
+
+ do
+ {
+ FT_Bool is_serif;
+
+
+ /* check for roundness of segment */
+ if ( seg->flags & AF_EDGE_ROUND )
+ is_round++;
+ else
+ is_straight++;
+
+ /* check for links -- if seg->serif is set, then seg->link must */
+ /* be ignored */
+ is_serif = (FT_Bool)( seg->serif && seg->serif->edge != edge );
+
+ if ( seg->link || is_serif )
+ {
+ AF_Edge edge2;
+ AF_Segment seg2;
+
+
+ edge2 = edge->link;
+ seg2 = seg->link;
+
+ if ( is_serif )
+ {
+ seg2 = seg->serif;
+ edge2 = edge->serif;
+ }
+
+ if ( edge2 )
+ {
+ FT_Pos edge_delta;
+ FT_Pos seg_delta;
+
+
+ edge_delta = edge->fpos - edge2->fpos;
+ if ( edge_delta < 0 )
+ edge_delta = -edge_delta;
+
+ seg_delta = AF_SEGMENT_DIST( seg, seg2 );
+
+ if ( seg_delta < edge_delta )
+ edge2 = seg2->edge;
+ }
+ else
+ edge2 = seg2->edge;
+
+ if ( is_serif )
+ {
+ edge->serif = edge2;
+ edge2->flags |= AF_EDGE_SERIF;
+ }
+ else
+ edge->link = edge2;
+ }
+
+ seg = seg->edge_next;
+
+ } while ( seg != edge->first );
+
+ /* set the round/straight flags */
+ edge->flags = AF_EDGE_NORMAL;
+
+ if ( is_round > 0 && is_round >= is_straight )
+ edge->flags |= AF_EDGE_ROUND;
+
+ /* get rid of serifs if link is set */
+ /* XXX: This gets rid of many unpleasant artefacts! */
+ /* Example: the `c' in cour.pfa at size 13 */
+
+ if ( edge->serif && edge->link )
+ edge->serif = 0;
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ static FT_Error
+ af_cjk_hints_detect_features( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ FT_Error error;
+
+
+ error = af_cjk_hints_compute_segments( hints, dim );
+ if ( !error )
+ {
+ af_cjk_hints_link_segments( hints, dim );
+
+ error = af_cjk_hints_compute_edges( hints, dim );
+ }
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ af_cjk_hints_init( AF_GlyphHints hints,
+ AF_LatinMetrics metrics )
+ {
+ FT_Render_Mode mode;
+ FT_UInt32 scaler_flags, other_flags;
+
+
+ af_glyph_hints_rescale( hints, (AF_ScriptMetrics)metrics );
+
+ /*
+ * correct x_scale and y_scale when needed, since they may have
+ * been modified af_cjk_scale_dim above
+ */
+ hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale;
+ hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta;
+ hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale;
+ hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta;
+
+ /* compute flags depending on render mode, etc. */
+ mode = metrics->root.scaler.render_mode;
+
+#ifdef AF_USE_WARPER
+ if ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V )
+ metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL;
+#endif
+
+ scaler_flags = hints->scaler_flags;
+ other_flags = 0;
+
+ /*
+ * We snap the width of vertical stems for the monochrome and
+ * horizontal LCD rendering targets only.
+ */
+ if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD )
+ other_flags |= AF_LATIN_HINTS_HORZ_SNAP;
+
+ /*
+ * We snap the width of horizontal stems for the monochrome and
+ * vertical LCD rendering targets only.
+ */
+ if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V )
+ other_flags |= AF_LATIN_HINTS_VERT_SNAP;
+
+ /*
+ * We adjust stems to full pixels only if we don't use the `light' mode.
+ */
+ if ( mode != FT_RENDER_MODE_LIGHT )
+ other_flags |= AF_LATIN_HINTS_STEM_ADJUST;
+
+ if ( mode == FT_RENDER_MODE_MONO )
+ other_flags |= AF_LATIN_HINTS_MONO;
+
+ scaler_flags |= AF_SCALER_FLAG_NO_ADVANCE;
+
+ hints->scaler_flags = scaler_flags;
+ hints->other_flags = other_flags;
+
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** C J K G L Y P H G R I D - F I T T I N G *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* snap a given width in scaled coordinates to one of the */
+ /* current standard widths */
+
+ static FT_Pos
+ af_cjk_snap_width( AF_Width widths,
+ FT_Int count,
+ FT_Pos width )
+ {
+ int n;
+ FT_Pos best = 64 + 32 + 2;
+ FT_Pos reference = width;
+ FT_Pos scaled;
+
+
+ for ( n = 0; n < count; n++ )
+ {
+ FT_Pos w;
+ FT_Pos dist;
+
+
+ w = widths[n].cur;
+ dist = width - w;
+ if ( dist < 0 )
+ dist = -dist;
+ if ( dist < best )
+ {
+ best = dist;
+ reference = w;
+ }
+ }
+
+ scaled = FT_PIX_ROUND( reference );
+
+ if ( width >= reference )
+ {
+ if ( width < scaled + 48 )
+ width = reference;
+ }
+ else
+ {
+ if ( width > scaled - 48 )
+ width = reference;
+ }
+
+ return width;
+ }
+
+
+ /* compute the snapped width of a given stem */
+
+ static FT_Pos
+ af_cjk_compute_stem_width( AF_GlyphHints hints,
+ AF_Dimension dim,
+ FT_Pos width,
+ AF_Edge_Flags base_flags,
+ AF_Edge_Flags stem_flags )
+ {
+ AF_LatinMetrics metrics = (AF_LatinMetrics) hints->metrics;
+ AF_LatinAxis axis = & metrics->axis[dim];
+ FT_Pos dist = width;
+ FT_Int sign = 0;
+ FT_Int vertical = ( dim == AF_DIMENSION_VERT );
+
+ FT_UNUSED( base_flags );
+ FT_UNUSED( stem_flags );
+
+
+ if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
+ return width;
+
+ if ( dist < 0 )
+ {
+ dist = -width;
+ sign = 1;
+ }
+
+ if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
+ ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
+ {
+ /* smooth hinting process: very lightly quantize the stem width */
+
+ if ( axis->width_count > 0 )
+ {
+ if ( FT_ABS( dist - axis->widths[0].cur ) < 40 )
+ {
+ dist = axis->widths[0].cur;
+ if ( dist < 48 )
+ dist = 48;
+
+ goto Done_Width;
+ }
+ }
+
+ if ( dist < 54 )
+ dist += ( 54 - dist ) / 2 ;
+ else if ( dist < 3 * 64 )
+ {
+ FT_Pos delta;
+
+
+ delta = dist & 63;
+ dist &= -64;
+
+ if ( delta < 10 )
+ dist += delta;
+ else if ( delta < 22 )
+ dist += 10;
+ else if ( delta < 42 )
+ dist += delta;
+ else if ( delta < 54 )
+ dist += 54;
+ else
+ dist += delta;
+ }
+ }
+ else
+ {
+ /* strong hinting process: snap the stem width to integer pixels */
+
+ dist = af_cjk_snap_width( axis->widths, axis->width_count, dist );
+
+ if ( vertical )
+ {
+ /* in the case of vertical hinting, always round */
+ /* the stem heights to integer pixels */
+
+ if ( dist >= 64 )
+ dist = ( dist + 16 ) & ~63;
+ else
+ dist = 64;
+ }
+ else
+ {
+ if ( AF_LATIN_HINTS_DO_MONO( hints ) )
+ {
+ /* monochrome horizontal hinting: snap widths to integer pixels */
+ /* with a different threshold */
+
+ if ( dist < 64 )
+ dist = 64;
+ else
+ dist = ( dist + 32 ) & ~63;
+ }
+ else
+ {
+ /* for horizontal anti-aliased hinting, we adopt a more subtle */
+ /* approach: we strengthen small stems, round stems whose size */
+ /* is between 1 and 2 pixels to an integer, otherwise nothing */
+
+ if ( dist < 48 )
+ dist = ( dist + 64 ) >> 1;
+
+ else if ( dist < 128 )
+ dist = ( dist + 22 ) & ~63;
+ else
+ /* round otherwise to prevent color fringes in LCD mode */
+ dist = ( dist + 32 ) & ~63;
+ }
+ }
+ }
+
+ Done_Width:
+ if ( sign )
+ dist = -dist;
+
+ return dist;
+ }
+
+
+ /* align one stem edge relative to the previous stem edge */
+
+ static void
+ af_cjk_align_linked_edge( AF_GlyphHints hints,
+ AF_Dimension dim,
+ AF_Edge base_edge,
+ AF_Edge stem_edge )
+ {
+ FT_Pos dist = stem_edge->opos - base_edge->opos;
+
+ FT_Pos fitted_width = af_cjk_compute_stem_width(
+ hints, dim, dist,
+ (AF_Edge_Flags)base_edge->flags,
+ (AF_Edge_Flags)stem_edge->flags );
+
+
+ stem_edge->pos = base_edge->pos + fitted_width;
+ }
+
+
+ static void
+ af_cjk_align_serif_edge( AF_GlyphHints hints,
+ AF_Edge base,
+ AF_Edge serif )
+ {
+ FT_UNUSED( hints );
+
+ serif->pos = base->pos + ( serif->opos - base->opos );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** E D G E H I N T I N G ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+#define AF_LIGHT_MODE_MAX_HORZ_GAP 9
+#define AF_LIGHT_MODE_MAX_VERT_GAP 15
+#define AF_LIGHT_MODE_MAX_DELTA_ABS 14
+
+
+ static FT_Pos
+ af_hint_normal_stem( AF_GlyphHints hints,
+ AF_Edge edge,
+ AF_Edge edge2,
+ FT_Pos anchor,
+ AF_Dimension dim )
+ {
+ FT_Pos org_len, cur_len, org_center;
+ FT_Pos cur_pos1, cur_pos2;
+ FT_Pos d_off1, u_off1, d_off2, u_off2, delta;
+ FT_Pos offset;
+ FT_Pos threshold = 64;
+
+
+ if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
+ {
+ if ( ( edge->flags & AF_EDGE_ROUND ) &&
+ ( edge2->flags & AF_EDGE_ROUND ) )
+ {
+ if ( dim == AF_DIMENSION_VERT )
+ threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP;
+ else
+ threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP;
+ }
+ else
+ {
+ if ( dim == AF_DIMENSION_VERT )
+ threshold = 64 - AF_LIGHT_MODE_MAX_HORZ_GAP / 3;
+ else
+ threshold = 64 - AF_LIGHT_MODE_MAX_VERT_GAP / 3;
+ }
+ }
+
+ org_len = edge2->opos - edge->opos;
+ cur_len = af_cjk_compute_stem_width( hints, dim, org_len,
+ (AF_Edge_Flags)edge->flags,
+ (AF_Edge_Flags)edge2->flags );
+
+ org_center = ( edge->opos + edge2->opos ) / 2 + anchor;
+ cur_pos1 = org_center - cur_len / 2;
+ cur_pos2 = cur_pos1 + cur_len;
+ d_off1 = cur_pos1 - FT_PIX_FLOOR( cur_pos1 );
+ d_off2 = cur_pos2 - FT_PIX_FLOOR( cur_pos2 );
+ u_off1 = 64 - d_off1;
+ u_off2 = 64 - d_off2;
+ delta = 0;
+
+
+ if ( d_off1 == 0 || d_off2 == 0 )
+ goto Exit;
+
+ if ( cur_len <= threshold )
+ {
+ if ( d_off2 < cur_len )
+ {
+ if ( u_off1 <= d_off2 )
+ delta = u_off1;
+ else
+ delta = -d_off2;
+ }
+
+ goto Exit;
+ }
+
+ if ( threshold < 64 )
+ {
+ if ( d_off1 >= threshold || u_off1 >= threshold ||
+ d_off2 >= threshold || u_off2 >= threshold )
+ goto Exit;
+ }
+
+ offset = cur_len % 64;
+
+ if ( offset < 32 )
+ {
+ if ( u_off1 <= offset || d_off2 <= offset )
+ goto Exit;
+ }
+ else
+ offset = 64 - threshold;
+
+ d_off1 = threshold - u_off1;
+ u_off1 = u_off1 - offset;
+ u_off2 = threshold - d_off2;
+ d_off2 = d_off2 - offset;
+
+ if ( d_off1 <= u_off1 )
+ u_off1 = -d_off1;
+
+ if ( d_off2 <= u_off2 )
+ u_off2 = -d_off2;
+
+ if ( FT_ABS( u_off1 ) <= FT_ABS( u_off2 ) )
+ delta = u_off1;
+ else
+ delta = u_off2;
+
+ Exit:
+
+#if 1
+ if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) )
+ {
+ if ( delta > AF_LIGHT_MODE_MAX_DELTA_ABS )
+ delta = AF_LIGHT_MODE_MAX_DELTA_ABS;
+ else if ( delta < -AF_LIGHT_MODE_MAX_DELTA_ABS )
+ delta = -AF_LIGHT_MODE_MAX_DELTA_ABS;
+ }
+#endif
+
+ cur_pos1 += delta;
+
+ if ( edge->opos < edge2->opos )
+ {
+ edge->pos = cur_pos1;
+ edge2->pos = cur_pos1 + cur_len;
+ }
+ else
+ {
+ edge->pos = cur_pos1 + cur_len;
+ edge2->pos = cur_pos1;
+ }
+
+ return delta;
+ }
+
+
+ static void
+ af_cjk_hint_edges( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_AxisHints axis = &hints->axis[dim];
+ AF_Edge edges = axis->edges;
+ AF_Edge edge_limit = edges + axis->num_edges;
+ FT_Int n_edges;
+ AF_Edge edge;
+ AF_Edge anchor = 0;
+ FT_Pos delta = 0;
+ FT_Int skipped = 0;
+
+
+ /* now we align all stem edges. */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ AF_Edge edge2;
+
+
+ if ( edge->flags & AF_EDGE_DONE )
+ continue;
+
+ /* skip all non-stem edges */
+ edge2 = edge->link;
+ if ( !edge2 )
+ {
+ skipped++;
+ continue;
+ }
+
+ /* now align the stem */
+
+ if ( edge2 < edge )
+ {
+ af_cjk_align_linked_edge( hints, dim, edge2, edge );
+ edge->flags |= AF_EDGE_DONE;
+ continue;
+ }
+
+ if ( dim != AF_DIMENSION_VERT && !anchor )
+ {
+
+#if 0
+ if ( fixedpitch )
+ {
+ AF_Edge left = edge;
+ AF_Edge right = edge_limit - 1;
+ AF_EdgeRec left1, left2, right1, right2;
+ FT_Pos target, center1, center2;
+ FT_Pos delta1, delta2, d1, d2;
+
+
+ while ( right > left && !right->link )
+ right--;
+
+ left1 = *left;
+ left2 = *left->link;
+ right1 = *right->link;
+ right2 = *right;
+
+ delta = ( ( ( hinter->pp2.x + 32 ) & -64 ) - hinter->pp2.x ) / 2;
+ target = left->opos + ( right->opos - left->opos ) / 2 + delta - 16;
+
+ delta1 = delta;
+ delta1 += af_hint_normal_stem( hints, left, left->link,
+ delta1, 0 );
+
+ if ( left->link != right )
+ af_hint_normal_stem( hints, right->link, right, delta1, 0 );
+
+ center1 = left->pos + ( right->pos - left->pos ) / 2;
+
+ if ( center1 >= target )
+ delta2 = delta - 32;
+ else
+ delta2 = delta + 32;
+
+ delta2 += af_hint_normal_stem( hints, &left1, &left2, delta2, 0 );
+
+ if ( delta1 != delta2 )
+ {
+ if ( left->link != right )
+ af_hint_normal_stem( hints, &right1, &right2, delta2, 0 );
+
+ center2 = left1.pos + ( right2.pos - left1.pos ) / 2;
+
+ d1 = center1 - target;
+ d2 = center2 - target;
+
+ if ( FT_ABS( d2 ) < FT_ABS( d1 ) )
+ {
+ left->pos = left1.pos;
+ left->link->pos = left2.pos;
+
+ if ( left->link != right )
+ {
+ right->link->pos = right1.pos;
+ right->pos = right2.pos;
+ }
+
+ delta1 = delta2;
+ }
+ }
+
+ delta = delta1;
+ right->link->flags |= AF_EDGE_DONE;
+ right->flags |= AF_EDGE_DONE;
+ }
+ else
+
+#endif /* 0 */
+
+ delta = af_hint_normal_stem( hints, edge, edge2, 0,
+ AF_DIMENSION_HORZ );
+ }
+ else
+ af_hint_normal_stem( hints, edge, edge2, delta, dim );
+
+#if 0
+ printf( "stem (%d,%d) adjusted (%.1f,%.1f)\n",
+ edge - edges, edge2 - edges,
+ ( edge->pos - edge->opos ) / 64.0,
+ ( edge2->pos - edge2->opos ) / 64.0 );
+#endif
+
+ anchor = edge;
+ edge->flags |= AF_EDGE_DONE;
+ edge2->flags |= AF_EDGE_DONE;
+ }
+
+ /* make sure that lowercase m's maintain their symmetry */
+
+ /* In general, lowercase m's have six vertical edges if they are sans */
+ /* serif, or twelve if they are with serifs. This implementation is */
+ /* based on that assumption, and seems to work very well with most */
+ /* faces. However, if for a certain face this assumption is not */
+ /* true, the m is just rendered like before. In addition, any stem */
+ /* correction will only be applied to symmetrical glyphs (even if the */
+ /* glyph is not an m), so the potential for unwanted distortion is */
+ /* relatively low. */
+
+ /* We don't handle horizontal edges since we can't easily assure that */
+ /* the third (lowest) stem aligns with the base line; it might end up */
+ /* one pixel higher or lower. */
+
+ n_edges = edge_limit - edges;
+ if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) )
+ {
+ AF_Edge edge1, edge2, edge3;
+ FT_Pos dist1, dist2, span;
+
+
+ if ( n_edges == 6 )
+ {
+ edge1 = edges;
+ edge2 = edges + 2;
+ edge3 = edges + 4;
+ }
+ else
+ {
+ edge1 = edges + 1;
+ edge2 = edges + 5;
+ edge3 = edges + 9;
+ }
+
+ dist1 = edge2->opos - edge1->opos;
+ dist2 = edge3->opos - edge2->opos;
+
+ span = dist1 - dist2;
+ if ( span < 0 )
+ span = -span;
+
+ if ( edge1->link == edge1 + 1 &&
+ edge2->link == edge2 + 1 &&
+ edge3->link == edge3 + 1 && span < 8 )
+ {
+ delta = edge3->pos - ( 2 * edge2->pos - edge1->pos );
+ edge3->pos -= delta;
+ if ( edge3->link )
+ edge3->link->pos -= delta;
+
+ /* move the serifs along with the stem */
+ if ( n_edges == 12 )
+ {
+ ( edges + 8 )->pos -= delta;
+ ( edges + 11 )->pos -= delta;
+ }
+
+ edge3->flags |= AF_EDGE_DONE;
+ if ( edge3->link )
+ edge3->link->flags |= AF_EDGE_DONE;
+ }
+ }
+
+ if ( !skipped )
+ return;
+
+ /*
+ * now hint the remaining edges (serifs and single) in order
+ * to complete our processing
+ */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ if ( edge->flags & AF_EDGE_DONE )
+ continue;
+
+ if ( edge->serif )
+ {
+ af_cjk_align_serif_edge( hints, edge->serif, edge );
+ edge->flags |= AF_EDGE_DONE;
+ skipped--;
+ }
+ }
+
+ if ( !skipped )
+ return;
+
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ AF_Edge before, after;
+
+
+ if ( edge->flags & AF_EDGE_DONE )
+ continue;
+
+ before = after = edge;
+
+ while ( --before >= edges )
+ if ( before->flags & AF_EDGE_DONE )
+ break;
+
+ while ( ++after < edge_limit )
+ if ( after->flags & AF_EDGE_DONE )
+ break;
+
+ if ( before >= edges || after < edge_limit )
+ {
+ if ( before < edges )
+ af_cjk_align_serif_edge( hints, after, edge );
+ else if ( after >= edge_limit )
+ af_cjk_align_serif_edge( hints, before, edge );
+ else
+ {
+ if ( after->fpos == before->fpos )
+ edge->pos = before->pos;
+ else
+ edge->pos = before->pos +
+ FT_MulDiv( edge->fpos - before->fpos,
+ after->pos - before->pos,
+ after->fpos - before->fpos );
+ }
+ }
+ }
+ }
+
+
+ static void
+ af_cjk_align_edge_points( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_AxisHints axis = & hints->axis[dim];
+ AF_Edge edges = axis->edges;
+ AF_Edge edge_limit = edges + axis->num_edges;
+ AF_Edge edge;
+ FT_Bool snapping;
+
+
+ snapping = FT_BOOL( ( dim == AF_DIMENSION_HORZ &&
+ AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) ||
+ ( dim == AF_DIMENSION_VERT &&
+ AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) );
+
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ /* move the points of each segment */
+ /* in each edge to the edge's position */
+ AF_Segment seg = edge->first;
+
+
+ if ( snapping )
+ {
+ do
+ {
+ AF_Point point = seg->first;
+
+
+ for (;;)
+ {
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ point->x = edge->pos;
+ point->flags |= AF_FLAG_TOUCH_X;
+ }
+ else
+ {
+ point->y = edge->pos;
+ point->flags |= AF_FLAG_TOUCH_Y;
+ }
+
+ if ( point == seg->last )
+ break;
+
+ point = point->next;
+ }
+
+ seg = seg->edge_next;
+
+ } while ( seg != edge->first );
+ }
+ else
+ {
+ FT_Pos delta = edge->pos - edge->opos;
+
+
+ do
+ {
+ AF_Point point = seg->first;
+
+
+ for (;;)
+ {
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ point->x += delta;
+ point->flags |= AF_FLAG_TOUCH_X;
+ }
+ else
+ {
+ point->y += delta;
+ point->flags |= AF_FLAG_TOUCH_Y;
+ }
+
+ if ( point == seg->last )
+ break;
+
+ point = point->next;
+ }
+
+ seg = seg->edge_next;
+
+ } while ( seg != edge->first );
+ }
+ }
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ af_cjk_hints_apply( AF_GlyphHints hints,
+ FT_Outline* outline,
+ AF_LatinMetrics metrics )
+ {
+ FT_Error error;
+ int dim;
+
+ FT_UNUSED( metrics );
+
+
+ error = af_glyph_hints_reload( hints, outline, 0 );
+ if ( error )
+ goto Exit;
+
+ /* analyze glyph outline */
+ if ( AF_HINTS_DO_HORIZONTAL( hints ) )
+ {
+ error = af_cjk_hints_detect_features( hints, AF_DIMENSION_HORZ );
+ if ( error )
+ goto Exit;
+ }
+
+ if ( AF_HINTS_DO_VERTICAL( hints ) )
+ {
+ error = af_cjk_hints_detect_features( hints, AF_DIMENSION_VERT );
+ if ( error )
+ goto Exit;
+ }
+
+ /* grid-fit the outline */
+ for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
+ {
+ if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) ||
+ ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) )
+ {
+
+#ifdef AF_USE_WARPER
+ if ( dim == AF_DIMENSION_HORZ &&
+ metrics->root.scaler.render_mode == FT_RENDER_MODE_NORMAL )
+ {
+ AF_WarperRec warper;
+ FT_Fixed scale;
+ FT_Pos delta;
+
+
+ af_warper_compute( &warper, hints, dim, &scale, &delta );
+ af_glyph_hints_scale_dim( hints, dim, scale, delta );
+ continue;
+ }
+#endif /* AF_USE_WARPER */
+
+ af_cjk_hint_edges( hints, (AF_Dimension)dim );
+ af_cjk_align_edge_points( hints, (AF_Dimension)dim );
+ af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim );
+ af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim );
+ }
+ }
+
+#if 0
+ af_glyph_hints_dump_points( hints );
+ af_glyph_hints_dump_segments( hints );
+ af_glyph_hints_dump_edges( hints );
+#endif
+
+ af_glyph_hints_save( hints, outline );
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** C J K S C R I P T C L A S S *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ static const AF_Script_UniRangeRec af_cjk_uniranges[] =
+ {
+#if 0
+ { 0x0100UL, 0xFFFFUL }, /* why this? */
+#endif
+ { 0x2E80UL, 0x2EFFUL }, /* CJK Radicals Supplement */
+ { 0x2F00UL, 0x2FDFUL }, /* Kangxi Radicals */
+ { 0x3000UL, 0x303FUL }, /* CJK Symbols and Punctuation */
+ { 0x3040UL, 0x309FUL }, /* Hiragana */
+ { 0x30A0UL, 0x30FFUL }, /* Katakana */
+ { 0x3100UL, 0x312FUL }, /* Bopomofo */
+ { 0x3130UL, 0x318FUL }, /* Hangul Compatibility Jamo */
+ { 0x31A0UL, 0x31BFUL }, /* Bopomofo Extended */
+ { 0x31C0UL, 0x31EFUL }, /* CJK Strokes */
+ { 0x31F0UL, 0x31FFUL }, /* Katakana Phonetic Extensions */
+ { 0x3200UL, 0x32FFUL }, /* Enclosed CJK Letters and Months */
+ { 0x3300UL, 0x33FFUL }, /* CJK Compatibility */
+ { 0x3400UL, 0x4DBFUL }, /* CJK Unified Ideographs Extension A */
+ { 0x4DC0UL, 0x4DFFUL }, /* Yijing Hexagram Symbols */
+ { 0x4E00UL, 0x9FFFUL }, /* CJK Unified Ideographs */
+ { 0xF900UL, 0xFAFFUL }, /* CJK Compatibility Ideographs */
+ { 0xFE30UL, 0xFE4FUL }, /* CJK Compatibility Forms */
+ { 0xFF00UL, 0xFFEFUL }, /* Halfwidth and Fullwidth Forms */
+ { 0x20000UL, 0x2A6DFUL }, /* CJK Unified Ideographs Extension B */
+ { 0x2F800UL, 0x2FA1FUL }, /* CJK Compatibility Ideographs Supplement */
+ { 0UL, 0UL }
+ };
+
+
+ FT_CALLBACK_TABLE_DEF const AF_ScriptClassRec
+ af_cjk_script_class =
+ {
+ AF_SCRIPT_CJK,
+ af_cjk_uniranges,
+
+ sizeof( AF_LatinMetricsRec ),
+
+ (AF_Script_InitMetricsFunc) af_cjk_metrics_init,
+ (AF_Script_ScaleMetricsFunc)af_cjk_metrics_scale,
+ (AF_Script_DoneMetricsFunc) NULL,
+
+ (AF_Script_InitHintsFunc) af_cjk_hints_init,
+ (AF_Script_ApplyHintsFunc) af_cjk_hints_apply
+ };
+
+#else /* !AF_CONFIG_OPTION_CJK */
+
+ static const AF_Script_UniRangeRec af_cjk_uniranges[] =
+ {
+ { 0, 0 }
+ };
+
+
+ FT_CALLBACK_TABLE_DEF const AF_ScriptClassRec
+ af_cjk_script_class =
+ {
+ AF_SCRIPT_CJK,
+ af_cjk_uniranges,
+
+ sizeof( AF_LatinMetricsRec ),
+
+ (AF_Script_InitMetricsFunc) NULL,
+ (AF_Script_ScaleMetricsFunc)NULL,
+ (AF_Script_DoneMetricsFunc) NULL,
+
+ (AF_Script_InitHintsFunc) NULL,
+ (AF_Script_ApplyHintsFunc) NULL
+ };
+
+#endif /* !AF_CONFIG_OPTION_CJK */
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/afcjk.h b/src/3rdparty/freetype/src/autofit/afcjk.h
new file mode 100644
index 0000000000..9f77fda143
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/afcjk.h
@@ -0,0 +1,58 @@
+/***************************************************************************/
+/* */
+/* afcjk.h */
+/* */
+/* Auto-fitter hinting routines for CJK script (specification). */
+/* */
+/* Copyright 2006, 2007 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AFCJK_H__
+#define __AFCJK_H__
+
+#include "afhints.h"
+
+
+FT_BEGIN_HEADER
+
+
+ /* the CJK-specific script class */
+
+ FT_CALLBACK_TABLE const AF_ScriptClassRec
+ af_cjk_script_class;
+
+
+ FT_LOCAL( FT_Error )
+ af_cjk_metrics_init( AF_LatinMetrics metrics,
+ FT_Face face );
+
+ FT_LOCAL( void )
+ af_cjk_metrics_scale( AF_LatinMetrics metrics,
+ AF_Scaler scaler );
+
+ FT_LOCAL( FT_Error )
+ af_cjk_hints_init( AF_GlyphHints hints,
+ AF_LatinMetrics metrics );
+
+ FT_LOCAL( FT_Error )
+ af_cjk_hints_apply( AF_GlyphHints hints,
+ FT_Outline* outline,
+ AF_LatinMetrics metrics );
+
+/* */
+
+FT_END_HEADER
+
+#endif /* __AFCJK_H__ */
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/afdummy.c b/src/3rdparty/freetype/src/autofit/afdummy.c
new file mode 100644
index 0000000000..ed96e96410
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/afdummy.c
@@ -0,0 +1,62 @@
+/***************************************************************************/
+/* */
+/* afdummy.c */
+/* */
+/* Auto-fitter dummy routines to be used if no hinting should be */
+/* performed (body). */
+/* */
+/* Copyright 2003, 2004, 2005 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "afdummy.h"
+#include "afhints.h"
+
+
+ static FT_Error
+ af_dummy_hints_init( AF_GlyphHints hints,
+ AF_ScriptMetrics metrics )
+ {
+ af_glyph_hints_rescale( hints,
+ metrics );
+ return 0;
+ }
+
+
+ static FT_Error
+ af_dummy_hints_apply( AF_GlyphHints hints,
+ FT_Outline* outline )
+ {
+ FT_UNUSED( hints );
+ FT_UNUSED( outline );
+
+ return 0;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF const AF_ScriptClassRec
+ af_dummy_script_class =
+ {
+ AF_SCRIPT_NONE,
+ NULL,
+
+ sizeof( AF_ScriptMetricsRec ),
+
+ (AF_Script_InitMetricsFunc) NULL,
+ (AF_Script_ScaleMetricsFunc)NULL,
+ (AF_Script_DoneMetricsFunc) NULL,
+
+ (AF_Script_InitHintsFunc) af_dummy_hints_init,
+ (AF_Script_ApplyHintsFunc) af_dummy_hints_apply
+ };
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/afdummy.h b/src/3rdparty/freetype/src/autofit/afdummy.h
new file mode 100644
index 0000000000..2a5faf8f85
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/afdummy.h
@@ -0,0 +1,43 @@
+/***************************************************************************/
+/* */
+/* afdummy.h */
+/* */
+/* Auto-fitter dummy routines to be used if no hinting should be */
+/* performed (specification). */
+/* */
+/* Copyright 2003, 2004, 2005 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AFDUMMY_H__
+#define __AFDUMMY_H__
+
+#include "aftypes.h"
+
+
+FT_BEGIN_HEADER
+
+ /* A dummy script metrics class used when no hinting should
+ * be performed. This is the default for non-latin glyphs!
+ */
+
+ FT_CALLBACK_TABLE const AF_ScriptClassRec
+ af_dummy_script_class;
+
+/* */
+
+FT_END_HEADER
+
+
+#endif /* __AFDUMMY_H__ */
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/aferrors.h b/src/3rdparty/freetype/src/autofit/aferrors.h
new file mode 100644
index 0000000000..c2ed5fe2ab
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/aferrors.h
@@ -0,0 +1,40 @@
+/***************************************************************************/
+/* */
+/* aferrors.h */
+/* */
+/* Autofitter error codes (specification only). */
+/* */
+/* Copyright 2005 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This file is used to define the Autofitter error enumeration */
+ /* constants. */
+ /* */
+ /*************************************************************************/
+
+#ifndef __AFERRORS_H__
+#define __AFERRORS_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX AF_Err_
+#define FT_ERR_BASE FT_Mod_Err_Autofit
+
+#include FT_ERRORS_H
+
+#endif /* __AFERRORS_H__ */
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/afglobal.c b/src/3rdparty/freetype/src/autofit/afglobal.c
new file mode 100644
index 0000000000..bfb9091bfd
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/afglobal.c
@@ -0,0 +1,289 @@
+/***************************************************************************/
+/* */
+/* afglobal.c */
+/* */
+/* Auto-fitter routines to compute global hinting values (body). */
+/* */
+/* Copyright 2003, 2004, 2005, 2006, 2007, 2008 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "afglobal.h"
+#include "afdummy.h"
+#include "aflatin.h"
+#include "afcjk.h"
+#include "afindic.h"
+
+#include "aferrors.h"
+
+#ifdef FT_OPTION_AUTOFIT2
+#include "aflatin2.h"
+#endif
+
+ /* populate this list when you add new scripts */
+ static AF_ScriptClass const af_script_classes[] =
+ {
+ &af_dummy_script_class,
+#ifdef FT_OPTION_AUTOFIT2
+ &af_latin2_script_class,
+#endif
+ &af_latin_script_class,
+ &af_cjk_script_class,
+ &af_indic_script_class,
+ NULL /* do not remove */
+ };
+
+ /* index of default script in `af_script_classes' */
+#define AF_SCRIPT_LIST_DEFAULT 2
+ /* indicates an uncovered glyph */
+#define AF_SCRIPT_LIST_NONE 255
+
+
+ /*
+ * Note that glyph_scripts[] is used to map each glyph into
+ * an index into the `af_script_classes' array.
+ *
+ */
+ typedef struct AF_FaceGlobalsRec_
+ {
+ FT_Face face;
+ FT_UInt glyph_count; /* same as face->num_glyphs */
+ FT_Byte* glyph_scripts;
+
+ AF_ScriptMetrics metrics[AF_SCRIPT_MAX];
+
+ } AF_FaceGlobalsRec;
+
+
+ /* Compute the script index of each glyph within a given face. */
+
+ static FT_Error
+ af_face_globals_compute_script_coverage( AF_FaceGlobals globals )
+ {
+ FT_Error error = AF_Err_Ok;
+ FT_Face face = globals->face;
+ FT_CharMap old_charmap = face->charmap;
+ FT_Byte* gscripts = globals->glyph_scripts;
+ FT_UInt ss;
+
+
+ /* the value 255 means `uncovered glyph' */
+ FT_MEM_SET( globals->glyph_scripts,
+ AF_SCRIPT_LIST_NONE,
+ globals->glyph_count );
+
+ error = FT_Select_Charmap( face, FT_ENCODING_UNICODE );
+ if ( error )
+ {
+ /*
+ * Ignore this error; we simply use the default script.
+ * XXX: Shouldn't we rather disable hinting?
+ */
+ error = AF_Err_Ok;
+ goto Exit;
+ }
+
+ /* scan each script in a Unicode charmap */
+ for ( ss = 0; af_script_classes[ss]; ss++ )
+ {
+ AF_ScriptClass clazz = af_script_classes[ss];
+ AF_Script_UniRange range;
+
+
+ if ( clazz->script_uni_ranges == NULL )
+ continue;
+
+ /*
+ * Scan all unicode points in the range and set the corresponding
+ * glyph script index.
+ */
+ for ( range = clazz->script_uni_ranges; range->first != 0; range++ )
+ {
+ FT_ULong charcode = range->first;
+ FT_UInt gindex;
+
+
+ gindex = FT_Get_Char_Index( face, charcode );
+
+ if ( gindex != 0 &&
+ gindex < globals->glyph_count &&
+ gscripts[gindex] == AF_SCRIPT_LIST_NONE )
+ {
+ gscripts[gindex] = (FT_Byte)ss;
+ }
+
+ for (;;)
+ {
+ charcode = FT_Get_Next_Char( face, charcode, &gindex );
+
+ if ( gindex == 0 || charcode > range->last )
+ break;
+
+ if ( gindex < globals->glyph_count &&
+ gscripts[gindex] == AF_SCRIPT_LIST_NONE )
+ {
+ gscripts[gindex] = (FT_Byte)ss;
+ }
+ }
+ }
+ }
+
+ Exit:
+ /*
+ * By default, all uncovered glyphs are set to the latin script.
+ * XXX: Shouldn't we disable hinting or do something similar?
+ */
+ {
+ FT_UInt nn;
+
+
+ for ( nn = 0; nn < globals->glyph_count; nn++ )
+ {
+ if ( gscripts[nn] == AF_SCRIPT_LIST_NONE )
+ gscripts[nn] = AF_SCRIPT_LIST_DEFAULT;
+ }
+ }
+
+ FT_Set_Charmap( face, old_charmap );
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ af_face_globals_new( FT_Face face,
+ AF_FaceGlobals *aglobals )
+ {
+ FT_Error error;
+ FT_Memory memory;
+ AF_FaceGlobals globals;
+
+
+ memory = face->memory;
+
+ if ( !FT_ALLOC( globals, sizeof ( *globals ) +
+ face->num_glyphs * sizeof ( FT_Byte ) ) )
+ {
+ globals->face = face;
+ globals->glyph_count = face->num_glyphs;
+ globals->glyph_scripts = (FT_Byte*)( globals + 1 );
+
+ error = af_face_globals_compute_script_coverage( globals );
+ if ( error )
+ {
+ af_face_globals_free( globals );
+ globals = NULL;
+ }
+ }
+
+ *aglobals = globals;
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_face_globals_free( AF_FaceGlobals globals )
+ {
+ if ( globals )
+ {
+ FT_Memory memory = globals->face->memory;
+ FT_UInt nn;
+
+
+ for ( nn = 0; nn < AF_SCRIPT_MAX; nn++ )
+ {
+ if ( globals->metrics[nn] )
+ {
+ AF_ScriptClass clazz = af_script_classes[nn];
+
+
+ FT_ASSERT( globals->metrics[nn]->clazz == clazz );
+
+ if ( clazz->script_metrics_done )
+ clazz->script_metrics_done( globals->metrics[nn] );
+
+ FT_FREE( globals->metrics[nn] );
+ }
+ }
+
+ globals->glyph_count = 0;
+ globals->glyph_scripts = NULL; /* no need to free this one! */
+ globals->face = NULL;
+
+ FT_FREE( globals );
+ }
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ af_face_globals_get_metrics( AF_FaceGlobals globals,
+ FT_UInt gindex,
+ FT_UInt options,
+ AF_ScriptMetrics *ametrics )
+ {
+ AF_ScriptMetrics metrics = NULL;
+ FT_UInt gidx;
+ AF_ScriptClass clazz;
+ FT_UInt script = options & 15;
+ const FT_UInt script_max = sizeof ( af_script_classes ) /
+ sizeof ( af_script_classes[0] );
+ FT_Error error = AF_Err_Ok;
+
+
+ if ( gindex >= globals->glyph_count )
+ {
+ error = AF_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ gidx = script;
+ if ( gidx == 0 || gidx + 1 >= script_max )
+ gidx = globals->glyph_scripts[gindex];
+
+ clazz = af_script_classes[gidx];
+ if ( script == 0 )
+ script = clazz->script;
+
+ metrics = globals->metrics[clazz->script];
+ if ( metrics == NULL )
+ {
+ /* create the global metrics object when needed */
+ FT_Memory memory = globals->face->memory;
+
+
+ if ( FT_ALLOC( metrics, clazz->script_metrics_size ) )
+ goto Exit;
+
+ metrics->clazz = clazz;
+
+ if ( clazz->script_metrics_init )
+ {
+ error = clazz->script_metrics_init( metrics, globals->face );
+ if ( error )
+ {
+ if ( clazz->script_metrics_done )
+ clazz->script_metrics_done( metrics );
+
+ FT_FREE( metrics );
+ goto Exit;
+ }
+ }
+
+ globals->metrics[clazz->script] = metrics;
+ }
+
+ Exit:
+ *ametrics = metrics;
+
+ return error;
+ }
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/afglobal.h b/src/3rdparty/freetype/src/autofit/afglobal.h
new file mode 100644
index 0000000000..cf52c08756
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/afglobal.h
@@ -0,0 +1,67 @@
+/***************************************************************************/
+/* */
+/* afglobal.h */
+/* */
+/* Auto-fitter routines to compute global hinting values */
+/* (specification). */
+/* */
+/* Copyright 2003, 2004, 2005, 2007 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AF_GLOBAL_H__
+#define __AF_GLOBAL_H__
+
+
+#include "aftypes.h"
+
+
+FT_BEGIN_HEADER
+
+
+ /************************************************************************/
+ /************************************************************************/
+ /***** *****/
+ /***** F A C E G L O B A L S *****/
+ /***** *****/
+ /************************************************************************/
+ /************************************************************************/
+
+
+ /*
+ * model the global hints data for a given face, decomposed into
+ * script-specific items
+ */
+ typedef struct AF_FaceGlobalsRec_* AF_FaceGlobals;
+
+
+ FT_LOCAL( FT_Error )
+ af_face_globals_new( FT_Face face,
+ AF_FaceGlobals *aglobals );
+
+ FT_LOCAL( FT_Error )
+ af_face_globals_get_metrics( AF_FaceGlobals globals,
+ FT_UInt gindex,
+ FT_UInt options,
+ AF_ScriptMetrics *ametrics );
+
+ FT_LOCAL( void )
+ af_face_globals_free( AF_FaceGlobals globals );
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __AF_GLOBALS_H__ */
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/afhints.c b/src/3rdparty/freetype/src/autofit/afhints.c
new file mode 100644
index 0000000000..8ab1761488
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/afhints.c
@@ -0,0 +1,1264 @@
+/***************************************************************************/
+/* */
+/* afhints.c */
+/* */
+/* Auto-fitter hinting routines (body). */
+/* */
+/* Copyright 2003, 2004, 2005, 2006, 2007, 2009 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "afhints.h"
+#include "aferrors.h"
+#include FT_INTERNAL_CALC_H
+
+
+ FT_LOCAL_DEF( FT_Error )
+ af_axis_hints_new_segment( AF_AxisHints axis,
+ FT_Memory memory,
+ AF_Segment *asegment )
+ {
+ FT_Error error = AF_Err_Ok;
+ AF_Segment segment = NULL;
+
+
+ if ( axis->num_segments >= axis->max_segments )
+ {
+ FT_Int old_max = axis->max_segments;
+ FT_Int new_max = old_max;
+ FT_Int big_max = FT_INT_MAX / sizeof ( *segment );
+
+
+ if ( old_max >= big_max )
+ {
+ error = AF_Err_Out_Of_Memory;
+ goto Exit;
+ }
+
+ new_max += ( new_max >> 2 ) + 4;
+ if ( new_max < old_max || new_max > big_max )
+ new_max = big_max;
+
+ if ( FT_RENEW_ARRAY( axis->segments, old_max, new_max ) )
+ goto Exit;
+
+ axis->max_segments = new_max;
+ }
+
+ segment = axis->segments + axis->num_segments++;
+
+ Exit:
+ *asegment = segment;
+ return error;
+ }
+
+
+ FT_LOCAL( FT_Error )
+ af_axis_hints_new_edge( AF_AxisHints axis,
+ FT_Int fpos,
+ AF_Direction dir,
+ FT_Memory memory,
+ AF_Edge *aedge )
+ {
+ FT_Error error = AF_Err_Ok;
+ AF_Edge edge = NULL;
+ AF_Edge edges;
+
+
+ if ( axis->num_edges >= axis->max_edges )
+ {
+ FT_Int old_max = axis->max_edges;
+ FT_Int new_max = old_max;
+ FT_Int big_max = FT_INT_MAX / sizeof ( *edge );
+
+
+ if ( old_max >= big_max )
+ {
+ error = AF_Err_Out_Of_Memory;
+ goto Exit;
+ }
+
+ new_max += ( new_max >> 2 ) + 4;
+ if ( new_max < old_max || new_max > big_max )
+ new_max = big_max;
+
+ if ( FT_RENEW_ARRAY( axis->edges, old_max, new_max ) )
+ goto Exit;
+
+ axis->max_edges = new_max;
+ }
+
+ edges = axis->edges;
+ edge = edges + axis->num_edges;
+
+ while ( edge > edges )
+ {
+ if ( edge[-1].fpos < fpos )
+ break;
+
+ /* we want the edge with same position and minor direction */
+ /* to appear before those in the major one in the list */
+ if ( edge[-1].fpos == fpos && dir == axis->major_dir )
+ break;
+
+ edge[0] = edge[-1];
+ edge--;
+ }
+
+ axis->num_edges++;
+
+ FT_ZERO( edge );
+ edge->fpos = (FT_Short)fpos;
+ edge->dir = (FT_Char)dir;
+
+ Exit:
+ *aedge = edge;
+ return error;
+ }
+
+
+#ifdef AF_DEBUG
+
+#include FT_CONFIG_STANDARD_LIBRARY_H
+
+ static const char*
+ af_dir_str( AF_Direction dir )
+ {
+ const char* result;
+
+
+ switch ( dir )
+ {
+ case AF_DIR_UP:
+ result = "up";
+ break;
+ case AF_DIR_DOWN:
+ result = "down";
+ break;
+ case AF_DIR_LEFT:
+ result = "left";
+ break;
+ case AF_DIR_RIGHT:
+ result = "right";
+ break;
+ default:
+ result = "none";
+ }
+
+ return result;
+ }
+
+
+#define AF_INDEX_NUM( ptr, base ) ( (ptr) ? ( (ptr) - (base) ) : -1 )
+
+
+ void
+ af_glyph_hints_dump_points( AF_GlyphHints hints )
+ {
+ AF_Point points = hints->points;
+ AF_Point limit = points + hints->num_points;
+ AF_Point point;
+
+
+ printf( "Table of points:\n" );
+ printf( " [ index | xorg | yorg | xscale | yscale "
+ "| xfit | yfit | flags ]\n" );
+
+ for ( point = points; point < limit; point++ )
+ {
+ printf( " [ %5d | %5d | %5d | %-5.2f | %-5.2f "
+ "| %-5.2f | %-5.2f | %c%c%c%c%c%c ]\n",
+ point - points,
+ point->fx,
+ point->fy,
+ point->ox/64.0,
+ point->oy/64.0,
+ point->x/64.0,
+ point->y/64.0,
+ ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) ? 'w' : ' ',
+ ( point->flags & AF_FLAG_INFLECTION ) ? 'i' : ' ',
+ ( point->flags & AF_FLAG_EXTREMA_X ) ? '<' : ' ',
+ ( point->flags & AF_FLAG_EXTREMA_Y ) ? 'v' : ' ',
+ ( point->flags & AF_FLAG_ROUND_X ) ? '(' : ' ',
+ ( point->flags & AF_FLAG_ROUND_Y ) ? 'u' : ' ');
+ }
+ printf( "\n" );
+ }
+
+
+ static const char*
+ af_edge_flags_to_string( AF_Edge_Flags flags )
+ {
+ static char temp[32];
+ int pos = 0;
+
+
+ if ( flags & AF_EDGE_ROUND )
+ {
+ ft_memcpy( temp + pos, "round", 5 );
+ pos += 5;
+ }
+ if ( flags & AF_EDGE_SERIF )
+ {
+ if ( pos > 0 )
+ temp[pos++] = ' ';
+ ft_memcpy( temp + pos, "serif", 5 );
+ pos += 5;
+ }
+ if ( pos == 0 )
+ return "normal";
+
+ temp[pos] = 0;
+
+ return temp;
+ }
+
+
+ /* A function to dump the array of linked segments. */
+ void
+ af_glyph_hints_dump_segments( AF_GlyphHints hints )
+ {
+ FT_Int dimension;
+
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AF_AxisHints axis = &hints->axis[dimension];
+ AF_Segment segments = axis->segments;
+ AF_Segment limit = segments + axis->num_segments;
+ AF_Segment seg;
+
+
+ printf ( "Table of %s segments:\n",
+ dimension == AF_DIMENSION_HORZ ? "vertical" : "horizontal" );
+ printf ( " [ index | pos | dir | link | serif |"
+ " height | extra | flags ]\n" );
+
+ for ( seg = segments; seg < limit; seg++ )
+ {
+ printf ( " [ %5d | %5.2g | %5s | %4d | %5d | %5d | %5d | %s ]\n",
+ seg - segments,
+ dimension == AF_DIMENSION_HORZ ? (int)seg->first->ox / 64.0
+ : (int)seg->first->oy / 64.0,
+ af_dir_str( (AF_Direction)seg->dir ),
+ AF_INDEX_NUM( seg->link, segments ),
+ AF_INDEX_NUM( seg->serif, segments ),
+ seg->height,
+ seg->height - ( seg->max_coord - seg->min_coord ),
+ af_edge_flags_to_string( seg->flags ) );
+ }
+ printf( "\n" );
+ }
+ }
+
+
+ void
+ af_glyph_hints_dump_edges( AF_GlyphHints hints )
+ {
+ FT_Int dimension;
+
+
+ for ( dimension = 1; dimension >= 0; dimension-- )
+ {
+ AF_AxisHints axis = &hints->axis[dimension];
+ AF_Edge edges = axis->edges;
+ AF_Edge limit = edges + axis->num_edges;
+ AF_Edge edge;
+
+
+ /*
+ * note: AF_DIMENSION_HORZ corresponds to _vertical_ edges
+ * since they have constant a X coordinate.
+ */
+ printf ( "Table of %s edges:\n",
+ dimension == AF_DIMENSION_HORZ ? "vertical" : "horizontal" );
+ printf ( " [ index | pos | dir | link |"
+ " serif | blue | opos | pos | flags ]\n" );
+
+ for ( edge = edges; edge < limit; edge++ )
+ {
+ printf ( " [ %5d | %5.2g | %5s | %4d |"
+ " %5d | %c | %5.2f | %5.2f | %s ]\n",
+ edge - edges,
+ (int)edge->opos / 64.0,
+ af_dir_str( (AF_Direction)edge->dir ),
+ AF_INDEX_NUM( edge->link, edges ),
+ AF_INDEX_NUM( edge->serif, edges ),
+ edge->blue_edge ? 'y' : 'n',
+ edge->opos / 64.0,
+ edge->pos / 64.0,
+ af_edge_flags_to_string( edge->flags ) );
+ }
+ printf( "\n" );
+ }
+ }
+
+#else /* !AF_DEBUG */
+
+ /* these empty stubs are only used to link the `ftgrid' test program */
+ /* when debugging is disabled */
+
+ void
+ af_glyph_hints_dump_points( AF_GlyphHints hints )
+ {
+ FT_UNUSED( hints );
+ }
+
+
+ void
+ af_glyph_hints_dump_segments( AF_GlyphHints hints )
+ {
+ FT_UNUSED( hints );
+ }
+
+
+ void
+ af_glyph_hints_dump_edges( AF_GlyphHints hints )
+ {
+ FT_UNUSED( hints );
+ }
+
+#endif /* !AF_DEBUG */
+
+
+ /* compute the direction value of a given vector */
+ FT_LOCAL_DEF( AF_Direction )
+ af_direction_compute( FT_Pos dx,
+ FT_Pos dy )
+ {
+ FT_Pos ll, ss; /* long and short arm lengths */
+ AF_Direction dir; /* candidate direction */
+
+
+ if ( dy >= dx )
+ {
+ if ( dy >= -dx )
+ {
+ dir = AF_DIR_UP;
+ ll = dy;
+ ss = dx;
+ }
+ else
+ {
+ dir = AF_DIR_LEFT;
+ ll = -dx;
+ ss = dy;
+ }
+ }
+ else /* dy < dx */
+ {
+ if ( dy >= -dx )
+ {
+ dir = AF_DIR_RIGHT;
+ ll = dx;
+ ss = dy;
+ }
+ else
+ {
+ dir = AF_DIR_DOWN;
+ ll = dy;
+ ss = dx;
+ }
+ }
+
+ ss *= 14;
+ if ( FT_ABS( ll ) <= FT_ABS( ss ) )
+ dir = AF_DIR_NONE;
+
+ return dir;
+ }
+
+
+ /* compute all inflex points in a given glyph */
+
+ static void
+ af_glyph_hints_compute_inflections( AF_GlyphHints hints )
+ {
+ AF_Point* contour = hints->contours;
+ AF_Point* contour_limit = contour + hints->num_contours;
+
+
+ /* do each contour separately */
+ for ( ; contour < contour_limit; contour++ )
+ {
+ AF_Point point = contour[0];
+ AF_Point first = point;
+ AF_Point start = point;
+ AF_Point end = point;
+ AF_Point before;
+ AF_Point after;
+ FT_Pos in_x, in_y, out_x, out_y;
+ AF_Angle orient_prev, orient_cur;
+ FT_Int finished = 0;
+
+
+ /* compute first segment in contour */
+ first = point;
+
+ start = end = first;
+ do
+ {
+ end = end->next;
+ if ( end == first )
+ goto Skip;
+
+ in_x = end->fx - start->fx;
+ in_y = end->fy - start->fy;
+
+ } while ( in_x == 0 && in_y == 0 );
+
+ /* extend the segment start whenever possible */
+ before = start;
+ do
+ {
+ do
+ {
+ start = before;
+ before = before->prev;
+ if ( before == first )
+ goto Skip;
+
+ out_x = start->fx - before->fx;
+ out_y = start->fy - before->fy;
+
+ } while ( out_x == 0 && out_y == 0 );
+
+ orient_prev = ft_corner_orientation( in_x, in_y, out_x, out_y );
+
+ } while ( orient_prev == 0 );
+
+ first = start;
+
+ in_x = out_x;
+ in_y = out_y;
+
+ /* now process all segments in the contour */
+ do
+ {
+ /* first, extend current segment's end whenever possible */
+ after = end;
+ do
+ {
+ do
+ {
+ end = after;
+ after = after->next;
+ if ( after == first )
+ finished = 1;
+
+ out_x = after->fx - end->fx;
+ out_y = after->fy - end->fy;
+
+ } while ( out_x == 0 && out_y == 0 );
+
+ orient_cur = ft_corner_orientation( in_x, in_y, out_x, out_y );
+
+ } while ( orient_cur == 0 );
+
+ if ( ( orient_prev + orient_cur ) == 0 )
+ {
+ /* we have an inflection point here */
+ do
+ {
+ start->flags |= AF_FLAG_INFLECTION;
+ start = start->next;
+
+ } while ( start != end );
+
+ start->flags |= AF_FLAG_INFLECTION;
+ }
+
+ start = end;
+ end = after;
+
+ orient_prev = orient_cur;
+ in_x = out_x;
+ in_y = out_y;
+
+ } while ( !finished );
+
+ Skip:
+ ;
+ }
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_glyph_hints_init( AF_GlyphHints hints,
+ FT_Memory memory )
+ {
+ FT_ZERO( hints );
+ hints->memory = memory;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_glyph_hints_done( AF_GlyphHints hints )
+ {
+ if ( hints && hints->memory )
+ {
+ FT_Memory memory = hints->memory;
+ int dim;
+
+
+ /*
+ * note that we don't need to free the segment and edge
+ * buffers, since they are really within the hints->points array
+ */
+ for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
+ {
+ AF_AxisHints axis = &hints->axis[dim];
+
+
+ axis->num_segments = 0;
+ axis->max_segments = 0;
+ FT_FREE( axis->segments );
+
+ axis->num_edges = 0;
+ axis->max_edges = 0;
+ FT_FREE( axis->edges );
+ }
+
+ FT_FREE( hints->contours );
+ hints->max_contours = 0;
+ hints->num_contours = 0;
+
+ FT_FREE( hints->points );
+ hints->num_points = 0;
+ hints->max_points = 0;
+
+ hints->memory = NULL;
+ }
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_glyph_hints_rescale( AF_GlyphHints hints,
+ AF_ScriptMetrics metrics )
+ {
+ hints->metrics = metrics;
+ hints->scaler_flags = metrics->scaler.flags;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ af_glyph_hints_reload( AF_GlyphHints hints,
+ FT_Outline* outline,
+ FT_Bool get_inflections )
+ {
+ FT_Error error = AF_Err_Ok;
+ AF_Point points;
+ FT_UInt old_max, new_max;
+ FT_Fixed x_scale = hints->x_scale;
+ FT_Fixed y_scale = hints->y_scale;
+ FT_Pos x_delta = hints->x_delta;
+ FT_Pos y_delta = hints->y_delta;
+ FT_Memory memory = hints->memory;
+
+
+ hints->num_points = 0;
+ hints->num_contours = 0;
+
+ hints->axis[0].num_segments = 0;
+ hints->axis[0].num_edges = 0;
+ hints->axis[1].num_segments = 0;
+ hints->axis[1].num_edges = 0;
+
+ /* first of all, reallocate the contours array when necessary */
+ new_max = (FT_UInt)outline->n_contours;
+ old_max = hints->max_contours;
+ if ( new_max > old_max )
+ {
+ new_max = ( new_max + 3 ) & ~3;
+
+ if ( FT_RENEW_ARRAY( hints->contours, old_max, new_max ) )
+ goto Exit;
+
+ hints->max_contours = new_max;
+ }
+
+ /*
+ * then reallocate the points arrays if necessary --
+ * note that we reserve two additional point positions, used to
+ * hint metrics appropriately
+ */
+ new_max = (FT_UInt)( outline->n_points + 2 );
+ old_max = hints->max_points;
+ if ( new_max > old_max )
+ {
+ new_max = ( new_max + 2 + 7 ) & ~7;
+
+ if ( FT_RENEW_ARRAY( hints->points, old_max, new_max ) )
+ goto Exit;
+
+ hints->max_points = new_max;
+ }
+
+ hints->num_points = outline->n_points;
+ hints->num_contours = outline->n_contours;
+
+ /* We can't rely on the value of `FT_Outline.flags' to know the fill */
+ /* direction used for a glyph, given that some fonts are broken (e.g., */
+ /* the Arphic ones). We thus recompute it each time we need to. */
+ /* */
+ hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_UP;
+ hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_LEFT;
+
+ if ( FT_Outline_Get_Orientation( outline ) == FT_ORIENTATION_POSTSCRIPT )
+ {
+ hints->axis[AF_DIMENSION_HORZ].major_dir = AF_DIR_DOWN;
+ hints->axis[AF_DIMENSION_VERT].major_dir = AF_DIR_RIGHT;
+ }
+
+ hints->x_scale = x_scale;
+ hints->y_scale = y_scale;
+ hints->x_delta = x_delta;
+ hints->y_delta = y_delta;
+
+ hints->xmin_delta = 0;
+ hints->xmax_delta = 0;
+
+ points = hints->points;
+ if ( hints->num_points == 0 )
+ goto Exit;
+
+ {
+ AF_Point point;
+ AF_Point point_limit = points + hints->num_points;
+
+
+ /* compute coordinates & Bezier flags, next and prev */
+ {
+ FT_Vector* vec = outline->points;
+ char* tag = outline->tags;
+ AF_Point first = points;
+ AF_Point end = points + outline->contours[0];
+ AF_Point prev = end;
+ FT_Int contour_index = 0;
+
+
+ for ( point = points; point < point_limit; point++, vec++, tag++ )
+ {
+ point->fx = (FT_Short)vec->x;
+ point->fy = (FT_Short)vec->y;
+ point->ox = point->x = FT_MulFix( vec->x, x_scale ) + x_delta;
+ point->oy = point->y = FT_MulFix( vec->y, y_scale ) + y_delta;
+
+ switch ( FT_CURVE_TAG( *tag ) )
+ {
+ case FT_CURVE_TAG_CONIC:
+ point->flags = AF_FLAG_CONIC;
+ break;
+ case FT_CURVE_TAG_CUBIC:
+ point->flags = AF_FLAG_CUBIC;
+ break;
+ default:
+ point->flags = 0;
+ }
+
+ point->prev = prev;
+ prev->next = point;
+ prev = point;
+
+ if ( point == end )
+ {
+ if ( ++contour_index < outline->n_contours )
+ {
+ first = point + 1;
+ end = points + outline->contours[contour_index];
+ prev = end;
+ }
+ }
+ }
+ }
+
+ /* set-up the contours array */
+ {
+ AF_Point* contour = hints->contours;
+ AF_Point* contour_limit = contour + hints->num_contours;
+ short* end = outline->contours;
+ short idx = 0;
+
+
+ for ( ; contour < contour_limit; contour++, end++ )
+ {
+ contour[0] = points + idx;
+ idx = (short)( end[0] + 1 );
+ }
+ }
+
+ /* compute directions of in & out vectors */
+ {
+ AF_Point first = points;
+ AF_Point prev = NULL;
+ FT_Pos in_x = 0;
+ FT_Pos in_y = 0;
+ AF_Direction in_dir = AF_DIR_NONE;
+
+
+ for ( point = points; point < point_limit; point++ )
+ {
+ AF_Point next;
+ FT_Pos out_x, out_y;
+
+
+ if ( point == first )
+ {
+ prev = first->prev;
+ in_x = first->fx - prev->fx;
+ in_y = first->fy - prev->fy;
+ in_dir = af_direction_compute( in_x, in_y );
+ first = prev + 1;
+ }
+
+ point->in_dir = (FT_Char)in_dir;
+
+ next = point->next;
+ out_x = next->fx - point->fx;
+ out_y = next->fy - point->fy;
+
+ in_dir = af_direction_compute( out_x, out_y );
+ point->out_dir = (FT_Char)in_dir;
+
+ if ( point->flags & ( AF_FLAG_CONIC | AF_FLAG_CUBIC ) )
+ {
+ Is_Weak_Point:
+ point->flags |= AF_FLAG_WEAK_INTERPOLATION;
+ }
+ else if ( point->out_dir == point->in_dir )
+ {
+ if ( point->out_dir != AF_DIR_NONE )
+ goto Is_Weak_Point;
+
+ if ( ft_corner_is_flat( in_x, in_y, out_x, out_y ) )
+ goto Is_Weak_Point;
+ }
+ else if ( point->in_dir == -point->out_dir )
+ goto Is_Weak_Point;
+
+ in_x = out_x;
+ in_y = out_y;
+ prev = point;
+ }
+ }
+ }
+
+ /* compute inflection points -- */
+ /* disabled due to no longer perceived benefits */
+ if ( 0 && get_inflections )
+ af_glyph_hints_compute_inflections( hints );
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_glyph_hints_save( AF_GlyphHints hints,
+ FT_Outline* outline )
+ {
+ AF_Point point = hints->points;
+ AF_Point limit = point + hints->num_points;
+ FT_Vector* vec = outline->points;
+ char* tag = outline->tags;
+
+
+ for ( ; point < limit; point++, vec++, tag++ )
+ {
+ vec->x = point->x;
+ vec->y = point->y;
+
+ if ( point->flags & AF_FLAG_CONIC )
+ tag[0] = FT_CURVE_TAG_CONIC;
+ else if ( point->flags & AF_FLAG_CUBIC )
+ tag[0] = FT_CURVE_TAG_CUBIC;
+ else
+ tag[0] = FT_CURVE_TAG_ON;
+ }
+ }
+
+
+ /****************************************************************
+ *
+ * EDGE POINT GRID-FITTING
+ *
+ ****************************************************************/
+
+
+ FT_LOCAL_DEF( void )
+ af_glyph_hints_align_edge_points( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_AxisHints axis = & hints->axis[dim];
+ AF_Segment segments = axis->segments;
+ AF_Segment segment_limit = segments + axis->num_segments;
+ AF_Segment seg;
+
+
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ for ( seg = segments; seg < segment_limit; seg++ )
+ {
+ AF_Edge edge = seg->edge;
+ AF_Point point, first, last;
+
+
+ if ( edge == NULL )
+ continue;
+
+ first = seg->first;
+ last = seg->last;
+ point = first;
+ for (;;)
+ {
+ point->x = edge->pos;
+ point->flags |= AF_FLAG_TOUCH_X;
+
+ if ( point == last )
+ break;
+
+ point = point->next;
+
+ }
+ }
+ }
+ else
+ {
+ for ( seg = segments; seg < segment_limit; seg++ )
+ {
+ AF_Edge edge = seg->edge;
+ AF_Point point, first, last;
+
+
+ if ( edge == NULL )
+ continue;
+
+ first = seg->first;
+ last = seg->last;
+ point = first;
+ for (;;)
+ {
+ point->y = edge->pos;
+ point->flags |= AF_FLAG_TOUCH_Y;
+
+ if ( point == last )
+ break;
+
+ point = point->next;
+ }
+ }
+ }
+ }
+
+
+ /****************************************************************
+ *
+ * STRONG POINT INTERPOLATION
+ *
+ ****************************************************************/
+
+
+ /* hint the strong points -- this is equivalent to the TrueType `IP' */
+ /* hinting instruction */
+
+ FT_LOCAL_DEF( void )
+ af_glyph_hints_align_strong_points( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_Point points = hints->points;
+ AF_Point point_limit = points + hints->num_points;
+ AF_AxisHints axis = &hints->axis[dim];
+ AF_Edge edges = axis->edges;
+ AF_Edge edge_limit = edges + axis->num_edges;
+ AF_Flags touch_flag;
+
+
+ if ( dim == AF_DIMENSION_HORZ )
+ touch_flag = AF_FLAG_TOUCH_X;
+ else
+ touch_flag = AF_FLAG_TOUCH_Y;
+
+ if ( edges < edge_limit )
+ {
+ AF_Point point;
+ AF_Edge edge;
+
+
+ for ( point = points; point < point_limit; point++ )
+ {
+ FT_Pos u, ou, fu; /* point position */
+ FT_Pos delta;
+
+
+ if ( point->flags & touch_flag )
+ continue;
+
+ /* if this point is candidate to weak interpolation, we */
+ /* interpolate it after all strong points have been processed */
+
+ if ( ( point->flags & AF_FLAG_WEAK_INTERPOLATION ) &&
+ !( point->flags & AF_FLAG_INFLECTION ) )
+ continue;
+
+ if ( dim == AF_DIMENSION_VERT )
+ {
+ u = point->fy;
+ ou = point->oy;
+ }
+ else
+ {
+ u = point->fx;
+ ou = point->ox;
+ }
+
+ fu = u;
+
+ /* is the point before the first edge? */
+ edge = edges;
+ delta = edge->fpos - u;
+ if ( delta >= 0 )
+ {
+ u = edge->pos - ( edge->opos - ou );
+ goto Store_Point;
+ }
+
+ /* is the point after the last edge? */
+ edge = edge_limit - 1;
+ delta = u - edge->fpos;
+ if ( delta >= 0 )
+ {
+ u = edge->pos + ( ou - edge->opos );
+ goto Store_Point;
+ }
+
+ {
+ FT_UInt min, max, mid;
+ FT_Pos fpos;
+
+
+ /* find enclosing edges */
+ min = 0;
+ max = edge_limit - edges;
+
+#if 1
+ /* for small edge counts, a linear search is better */
+ if ( max <= 8 )
+ {
+ FT_UInt nn;
+
+ for ( nn = 0; nn < max; nn++ )
+ if ( edges[nn].fpos >= u )
+ break;
+
+ if ( edges[nn].fpos == u )
+ {
+ u = edges[nn].pos;
+ goto Store_Point;
+ }
+ min = nn;
+ }
+ else
+#endif
+ while ( min < max )
+ {
+ mid = ( max + min ) >> 1;
+ edge = edges + mid;
+ fpos = edge->fpos;
+
+ if ( u < fpos )
+ max = mid;
+ else if ( u > fpos )
+ min = mid + 1;
+ else
+ {
+ /* we are on the edge */
+ u = edge->pos;
+ goto Store_Point;
+ }
+ }
+
+ {
+ AF_Edge before = edges + min - 1;
+ AF_Edge after = edges + min + 0;
+
+
+ /* assert( before && after && before != after ) */
+ if ( before->scale == 0 )
+ before->scale = FT_DivFix( after->pos - before->pos,
+ after->fpos - before->fpos );
+
+ u = before->pos + FT_MulFix( fu - before->fpos,
+ before->scale );
+ }
+ }
+
+ Store_Point:
+ /* save the point position */
+ if ( dim == AF_DIMENSION_HORZ )
+ point->x = u;
+ else
+ point->y = u;
+
+ point->flags |= touch_flag;
+ }
+ }
+ }
+
+
+ /****************************************************************
+ *
+ * WEAK POINT INTERPOLATION
+ *
+ ****************************************************************/
+
+
+ static void
+ af_iup_shift( AF_Point p1,
+ AF_Point p2,
+ AF_Point ref )
+ {
+ AF_Point p;
+ FT_Pos delta = ref->u - ref->v;
+
+ if ( delta == 0 )
+ return;
+
+ for ( p = p1; p < ref; p++ )
+ p->u = p->v + delta;
+
+ for ( p = ref + 1; p <= p2; p++ )
+ p->u = p->v + delta;
+ }
+
+
+ static void
+ af_iup_interp( AF_Point p1,
+ AF_Point p2,
+ AF_Point ref1,
+ AF_Point ref2 )
+ {
+ AF_Point p;
+ FT_Pos u;
+ FT_Pos v1 = ref1->v;
+ FT_Pos v2 = ref2->v;
+ FT_Pos d1 = ref1->u - v1;
+ FT_Pos d2 = ref2->u - v2;
+
+
+ if ( p1 > p2 )
+ return;
+
+ if ( v1 == v2 )
+ {
+ for ( p = p1; p <= p2; p++ )
+ {
+ u = p->v;
+
+ if ( u <= v1 )
+ u += d1;
+ else
+ u += d2;
+
+ p->u = u;
+ }
+ return;
+ }
+
+ if ( v1 < v2 )
+ {
+ for ( p = p1; p <= p2; p++ )
+ {
+ u = p->v;
+
+ if ( u <= v1 )
+ u += d1;
+ else if ( u >= v2 )
+ u += d2;
+ else
+ u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
+
+ p->u = u;
+ }
+ }
+ else
+ {
+ for ( p = p1; p <= p2; p++ )
+ {
+ u = p->v;
+
+ if ( u <= v2 )
+ u += d2;
+ else if ( u >= v1 )
+ u += d1;
+ else
+ u = ref1->u + FT_MulDiv( u - v1, ref2->u - ref1->u, v2 - v1 );
+
+ p->u = u;
+ }
+ }
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_glyph_hints_align_weak_points( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_Point points = hints->points;
+ AF_Point point_limit = points + hints->num_points;
+ AF_Point* contour = hints->contours;
+ AF_Point* contour_limit = contour + hints->num_contours;
+ AF_Flags touch_flag;
+ AF_Point point;
+ AF_Point end_point;
+ AF_Point first_point;
+
+
+ /* PASS 1: Move segment points to edge positions */
+
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ touch_flag = AF_FLAG_TOUCH_X;
+
+ for ( point = points; point < point_limit; point++ )
+ {
+ point->u = point->x;
+ point->v = point->ox;
+ }
+ }
+ else
+ {
+ touch_flag = AF_FLAG_TOUCH_Y;
+
+ for ( point = points; point < point_limit; point++ )
+ {
+ point->u = point->y;
+ point->v = point->oy;
+ }
+ }
+
+ point = points;
+
+ for ( ; contour < contour_limit; contour++ )
+ {
+ AF_Point first_touched, last_touched;
+
+
+ point = *contour;
+ end_point = point->prev;
+ first_point = point;
+
+ /* find first touched point */
+ for (;;)
+ {
+ if ( point > end_point ) /* no touched point in contour */
+ goto NextContour;
+
+ if ( point->flags & touch_flag )
+ break;
+
+ point++;
+ }
+
+ first_touched = point;
+ last_touched = point;
+
+ for (;;)
+ {
+ FT_ASSERT( point <= end_point &&
+ ( point->flags & touch_flag ) != 0 );
+
+ /* skip any touched neighbhours */
+ while ( point < end_point && ( point[1].flags & touch_flag ) != 0 )
+ point++;
+
+ last_touched = point;
+
+ /* find the next touched point, if any */
+ point ++;
+ for (;;)
+ {
+ if ( point > end_point )
+ goto EndContour;
+
+ if ( ( point->flags & touch_flag ) != 0 )
+ break;
+
+ point++;
+ }
+
+ /* interpolate between last_touched and point */
+ af_iup_interp( last_touched + 1, point - 1,
+ last_touched, point );
+ }
+
+ EndContour:
+ /* special case: only one point was touched */
+ if ( last_touched == first_touched )
+ {
+ af_iup_shift( first_point, end_point, first_touched );
+ }
+ else /* interpolate the last part */
+ {
+ if ( last_touched < end_point )
+ af_iup_interp( last_touched + 1, end_point,
+ last_touched, first_touched );
+
+ if ( first_touched > points )
+ af_iup_interp( first_point, first_touched - 1,
+ last_touched, first_touched );
+ }
+
+ NextContour:
+ ;
+ }
+
+ /* now save the interpolated values back to x/y */
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ for ( point = points; point < point_limit; point++ )
+ point->x = point->u;
+ }
+ else
+ {
+ for ( point = points; point < point_limit; point++ )
+ point->y = point->u;
+ }
+ }
+
+
+#ifdef AF_USE_WARPER
+
+ FT_LOCAL_DEF( void )
+ af_glyph_hints_scale_dim( AF_GlyphHints hints,
+ AF_Dimension dim,
+ FT_Fixed scale,
+ FT_Pos delta )
+ {
+ AF_Point points = hints->points;
+ AF_Point points_limit = points + hints->num_points;
+ AF_Point point;
+
+
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ for ( point = points; point < points_limit; point++ )
+ point->x = FT_MulFix( point->fx, scale ) + delta;
+ }
+ else
+ {
+ for ( point = points; point < points_limit; point++ )
+ point->y = FT_MulFix( point->fy, scale ) + delta;
+ }
+ }
+
+#endif /* AF_USE_WARPER */
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/afhints.h b/src/3rdparty/freetype/src/autofit/afhints.h
new file mode 100644
index 0000000000..675826835a
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/afhints.h
@@ -0,0 +1,333 @@
+/***************************************************************************/
+/* */
+/* afhints.h */
+/* */
+/* Auto-fitter hinting routines (specification). */
+/* */
+/* Copyright 2003, 2004, 2005, 2006, 2007, 2008 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AFHINTS_H__
+#define __AFHINTS_H__
+
+#include "aftypes.h"
+
+#define xxAF_SORT_SEGMENTS
+
+FT_BEGIN_HEADER
+
+ /*
+ * The definition of outline glyph hints. These are shared by all
+ * script analysis routines (until now).
+ */
+
+ typedef enum AF_Dimension_
+ {
+ AF_DIMENSION_HORZ = 0, /* x coordinates, */
+ /* i.e., vertical segments & edges */
+ AF_DIMENSION_VERT = 1, /* y coordinates, */
+ /* i.e., horizontal segments & edges */
+
+ AF_DIMENSION_MAX /* do not remove */
+
+ } AF_Dimension;
+
+
+ /* hint directions -- the values are computed so that two vectors are */
+ /* in opposite directions iff `dir1 + dir2 == 0' */
+ typedef enum AF_Direction_
+ {
+ AF_DIR_NONE = 4,
+ AF_DIR_RIGHT = 1,
+ AF_DIR_LEFT = -1,
+ AF_DIR_UP = 2,
+ AF_DIR_DOWN = -2
+
+ } AF_Direction;
+
+
+ /* point hint flags */
+ typedef enum AF_Flags_
+ {
+ AF_FLAG_NONE = 0,
+
+ /* point type flags */
+ AF_FLAG_CONIC = 1 << 0,
+ AF_FLAG_CUBIC = 1 << 1,
+ AF_FLAG_CONTROL = AF_FLAG_CONIC | AF_FLAG_CUBIC,
+
+ /* point extremum flags */
+ AF_FLAG_EXTREMA_X = 1 << 2,
+ AF_FLAG_EXTREMA_Y = 1 << 3,
+
+ /* point roundness flags */
+ AF_FLAG_ROUND_X = 1 << 4,
+ AF_FLAG_ROUND_Y = 1 << 5,
+
+ /* point touch flags */
+ AF_FLAG_TOUCH_X = 1 << 6,
+ AF_FLAG_TOUCH_Y = 1 << 7,
+
+ /* candidates for weak interpolation have this flag set */
+ AF_FLAG_WEAK_INTERPOLATION = 1 << 8,
+
+ /* all inflection points in the outline have this flag set */
+ AF_FLAG_INFLECTION = 1 << 9
+
+ } AF_Flags;
+
+
+ /* edge hint flags */
+ typedef enum AF_Edge_Flags_
+ {
+ AF_EDGE_NORMAL = 0,
+ AF_EDGE_ROUND = 1 << 0,
+ AF_EDGE_SERIF = 1 << 1,
+ AF_EDGE_DONE = 1 << 2
+
+ } AF_Edge_Flags;
+
+
+ typedef struct AF_PointRec_* AF_Point;
+ typedef struct AF_SegmentRec_* AF_Segment;
+ typedef struct AF_EdgeRec_* AF_Edge;
+
+
+ typedef struct AF_PointRec_
+ {
+ FT_UShort flags; /* point flags used by hinter */
+ FT_Char in_dir; /* direction of inwards vector */
+ FT_Char out_dir; /* direction of outwards vector */
+
+ FT_Pos ox, oy; /* original, scaled position */
+ FT_Short fx, fy; /* original, unscaled position (font units) */
+ FT_Pos x, y; /* current position */
+ FT_Pos u, v; /* current (x,y) or (y,x) depending on context */
+
+ AF_Point next; /* next point in contour */
+ AF_Point prev; /* previous point in contour */
+
+ } AF_PointRec;
+
+
+ typedef struct AF_SegmentRec_
+ {
+ FT_Byte flags; /* edge/segment flags for this segment */
+ FT_Char dir; /* segment direction */
+ FT_Short pos; /* position of segment */
+ FT_Short min_coord; /* minimum coordinate of segment */
+ FT_Short max_coord; /* maximum coordinate of segment */
+ FT_Short height; /* the hinted segment height */
+
+ AF_Edge edge; /* the segment's parent edge */
+ AF_Segment edge_next; /* link to next segment in parent edge */
+
+ AF_Segment link; /* (stem) link segment */
+ AF_Segment serif; /* primary segment for serifs */
+ FT_Pos num_linked; /* number of linked segments */
+ FT_Pos score; /* used during stem matching */
+ FT_Pos len; /* used during stem matching */
+
+ AF_Point first; /* first point in edge segment */
+ AF_Point last; /* last point in edge segment */
+ AF_Point* contour; /* ptr to first point of segment's contour */
+
+ } AF_SegmentRec;
+
+
+ typedef struct AF_EdgeRec_
+ {
+ FT_Short fpos; /* original, unscaled position (font units) */
+ FT_Pos opos; /* original, scaled position */
+ FT_Pos pos; /* current position */
+
+ FT_Byte flags; /* edge flags */
+ FT_Char dir; /* edge direction */
+ FT_Fixed scale; /* used to speed up interpolation between edges */
+ AF_Width blue_edge; /* non-NULL if this is a blue edge */
+
+ AF_Edge link;
+ AF_Edge serif;
+ FT_Short num_linked;
+
+ FT_Int score;
+
+ AF_Segment first;
+ AF_Segment last;
+
+ } AF_EdgeRec;
+
+
+ typedef struct AF_AxisHintsRec_
+ {
+ FT_Int num_segments;
+ FT_Int max_segments;
+ AF_Segment segments;
+#ifdef AF_SORT_SEGMENTS
+ FT_Int mid_segments;
+#endif
+
+ FT_Int num_edges;
+ FT_Int max_edges;
+ AF_Edge edges;
+
+ AF_Direction major_dir;
+
+ } AF_AxisHintsRec, *AF_AxisHints;
+
+
+ typedef struct AF_GlyphHintsRec_
+ {
+ FT_Memory memory;
+
+ FT_Fixed x_scale;
+ FT_Pos x_delta;
+
+ FT_Fixed y_scale;
+ FT_Pos y_delta;
+
+ FT_Pos edge_distance_threshold;
+
+ FT_Int max_points;
+ FT_Int num_points;
+ AF_Point points;
+
+ FT_Int max_contours;
+ FT_Int num_contours;
+ AF_Point* contours;
+
+ AF_AxisHintsRec axis[AF_DIMENSION_MAX];
+
+ FT_UInt32 scaler_flags; /* copy of scaler flags */
+ FT_UInt32 other_flags; /* free for script-specific */
+ /* implementations */
+ AF_ScriptMetrics metrics;
+
+ FT_Pos xmin_delta; /* used for warping */
+ FT_Pos xmax_delta;
+
+ } AF_GlyphHintsRec;
+
+
+#define AF_HINTS_TEST_SCALER( h, f ) ( (h)->scaler_flags & (f) )
+#define AF_HINTS_TEST_OTHER( h, f ) ( (h)->other_flags & (f) )
+
+
+#ifdef AF_DEBUG
+
+#define AF_HINTS_DO_HORIZONTAL( h ) \
+ ( !_af_debug_disable_horz_hints && \
+ !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_HORIZONTAL ) )
+
+#define AF_HINTS_DO_VERTICAL( h ) \
+ ( !_af_debug_disable_vert_hints && \
+ !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_VERTICAL ) )
+
+#define AF_HINTS_DO_ADVANCE( h ) \
+ !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_ADVANCE )
+
+#define AF_HINTS_DO_BLUES( h ) ( !_af_debug_disable_blue_hints )
+
+#else /* !AF_DEBUG */
+
+#define AF_HINTS_DO_HORIZONTAL( h ) \
+ !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_HORIZONTAL )
+
+#define AF_HINTS_DO_VERTICAL( h ) \
+ !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_VERTICAL )
+
+#define AF_HINTS_DO_ADVANCE( h ) \
+ !AF_HINTS_TEST_SCALER( h, AF_SCALER_FLAG_NO_ADVANCE )
+
+#define AF_HINTS_DO_BLUES( h ) 1
+
+#endif /* !AF_DEBUG */
+
+
+ FT_LOCAL( AF_Direction )
+ af_direction_compute( FT_Pos dx,
+ FT_Pos dy );
+
+
+ FT_LOCAL( FT_Error )
+ af_axis_hints_new_segment( AF_AxisHints axis,
+ FT_Memory memory,
+ AF_Segment *asegment );
+
+ FT_LOCAL( FT_Error)
+ af_axis_hints_new_edge( AF_AxisHints axis,
+ FT_Int fpos,
+ AF_Direction dir,
+ FT_Memory memory,
+ AF_Edge *edge );
+
+ FT_LOCAL( void )
+ af_glyph_hints_init( AF_GlyphHints hints,
+ FT_Memory memory );
+
+
+
+ /*
+ * recompute all AF_Point in a AF_GlyphHints from the definitions
+ * in a source outline
+ */
+ FT_LOCAL( void )
+ af_glyph_hints_rescale( AF_GlyphHints hints,
+ AF_ScriptMetrics metrics );
+
+ FT_LOCAL( FT_Error )
+ af_glyph_hints_reload( AF_GlyphHints hints,
+ FT_Outline* outline,
+ FT_Bool get_inflections );
+
+ FT_LOCAL( void )
+ af_glyph_hints_save( AF_GlyphHints hints,
+ FT_Outline* outline );
+
+ FT_LOCAL( void )
+ af_glyph_hints_align_edge_points( AF_GlyphHints hints,
+ AF_Dimension dim );
+
+ FT_LOCAL( void )
+ af_glyph_hints_align_strong_points( AF_GlyphHints hints,
+ AF_Dimension dim );
+
+ FT_LOCAL( void )
+ af_glyph_hints_align_weak_points( AF_GlyphHints hints,
+ AF_Dimension dim );
+
+#ifdef AF_USE_WARPER
+ FT_LOCAL( void )
+ af_glyph_hints_scale_dim( AF_GlyphHints hints,
+ AF_Dimension dim,
+ FT_Fixed scale,
+ FT_Pos delta );
+#endif
+
+ FT_LOCAL( void )
+ af_glyph_hints_done( AF_GlyphHints hints );
+
+/* */
+
+#define AF_SEGMENT_LEN( seg ) ( (seg)->max_coord - (seg)->min_coord )
+
+#define AF_SEGMENT_DIST( seg1, seg2 ) ( ( (seg1)->pos > (seg2)->pos ) \
+ ? (seg1)->pos - (seg2)->pos \
+ : (seg2)->pos - (seg1)->pos )
+
+
+FT_END_HEADER
+
+#endif /* __AFHINTS_H__ */
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/afindic.c b/src/3rdparty/freetype/src/autofit/afindic.c
new file mode 100644
index 0000000000..3d27f521b6
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/afindic.c
@@ -0,0 +1,134 @@
+/***************************************************************************/
+/* */
+/* afindic.c */
+/* */
+/* Auto-fitter hinting routines for Indic scripts (body). */
+/* */
+/* Copyright 2007 by */
+/* Rahul Bhalerao <rahul.bhalerao@redhat.com>, <b.rahul.pm@gmail.com>. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "aftypes.h"
+#include "aflatin.h"
+
+
+#ifdef AF_CONFIG_OPTION_INDIC
+
+#include "afindic.h"
+#include "aferrors.h"
+#include "afcjk.h"
+
+
+#ifdef AF_USE_WARPER
+#include "afwarp.h"
+#endif
+
+
+ static FT_Error
+ af_indic_metrics_init( AF_LatinMetrics metrics,
+ FT_Face face )
+ {
+ /* use CJK routines */
+ return af_cjk_metrics_init( metrics, face );
+ }
+
+
+ static void
+ af_indic_metrics_scale( AF_LatinMetrics metrics,
+ AF_Scaler scaler )
+ {
+ /* use CJK routines */
+ af_cjk_metrics_scale( metrics, scaler );
+ }
+
+
+ static FT_Error
+ af_indic_hints_init( AF_GlyphHints hints,
+ AF_LatinMetrics metrics )
+ {
+ /* use CJK routines */
+ return af_cjk_hints_init( hints, metrics );
+ }
+
+
+ static FT_Error
+ af_indic_hints_apply( AF_GlyphHints hints,
+ FT_Outline* outline,
+ AF_LatinMetrics metrics)
+ {
+ /* use CJK routines */
+ return af_cjk_hints_apply( hints, outline, metrics );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** I N D I C S C R I P T C L A S S *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ static const AF_Script_UniRangeRec af_indic_uniranges[] =
+ {
+#if 0
+ { 0x0100, 0xFFFF }, /* why this? */
+#endif
+ { 0x0900, 0x0DFF}, /* Indic Range */
+ { 0, 0 }
+ };
+
+
+ FT_CALLBACK_TABLE_DEF const AF_ScriptClassRec
+ af_indic_script_class =
+ {
+ AF_SCRIPT_INDIC,
+ af_indic_uniranges,
+
+ sizeof( AF_LatinMetricsRec ),
+
+ (AF_Script_InitMetricsFunc) af_indic_metrics_init,
+ (AF_Script_ScaleMetricsFunc)af_indic_metrics_scale,
+ (AF_Script_DoneMetricsFunc) NULL,
+
+ (AF_Script_InitHintsFunc) af_indic_hints_init,
+ (AF_Script_ApplyHintsFunc) af_indic_hints_apply
+ };
+
+#else /* !AF_CONFIG_OPTION_INDIC */
+
+ static const AF_Script_UniRangeRec af_indic_uniranges[] =
+ {
+ { 0, 0 }
+ };
+
+
+ FT_CALLBACK_TABLE_DEF const AF_ScriptClassRec
+ af_indic_script_class =
+ {
+ AF_SCRIPT_INDIC,
+ af_indic_uniranges,
+
+ sizeof( AF_LatinMetricsRec ),
+
+ (AF_Script_InitMetricsFunc) NULL,
+ (AF_Script_ScaleMetricsFunc)NULL,
+ (AF_Script_DoneMetricsFunc) NULL,
+
+ (AF_Script_InitHintsFunc) NULL,
+ (AF_Script_ApplyHintsFunc) NULL
+ };
+
+#endif /* !AF_CONFIG_OPTION_INDIC */
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/afindic.h b/src/3rdparty/freetype/src/autofit/afindic.h
new file mode 100644
index 0000000000..b242b26144
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/afindic.h
@@ -0,0 +1,41 @@
+/***************************************************************************/
+/* */
+/* afindic.h */
+/* */
+/* Auto-fitter hinting routines for Indic scripts (specification). */
+/* */
+/* Copyright 2007 by */
+/* Rahul Bhalerao <rahul.bhalerao@redhat.com>, <b.rahul.pm@gmail.com>. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AFINDIC_H__
+#define __AFINDIC_H__
+
+#include "afhints.h"
+
+
+FT_BEGIN_HEADER
+
+
+ /* the Indic-specific script class */
+
+ FT_CALLBACK_TABLE const AF_ScriptClassRec
+ af_indic_script_class;
+
+
+/* */
+
+FT_END_HEADER
+
+#endif /* __AFINDIC_H__ */
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/aflatin.c b/src/3rdparty/freetype/src/autofit/aflatin.c
new file mode 100644
index 0000000000..ba59e5b38c
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/aflatin.c
@@ -0,0 +1,2177 @@
+/***************************************************************************/
+/* */
+/* aflatin.c */
+/* */
+/* Auto-fitter hinting routines for latin script (body). */
+/* */
+/* Copyright 2003, 2004, 2005, 2006, 2007, 2008 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "aflatin.h"
+#include "aferrors.h"
+
+
+#ifdef AF_USE_WARPER
+#include "afwarp.h"
+#endif
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** L A T I N G L O B A L M E T R I C S *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_LOCAL_DEF( void )
+ af_latin_metrics_init_widths( AF_LatinMetrics metrics,
+ FT_Face face,
+ FT_ULong charcode )
+ {
+ /* scan the array of segments in each direction */
+ AF_GlyphHintsRec hints[1];
+
+
+ af_glyph_hints_init( hints, face->memory );
+
+ metrics->axis[AF_DIMENSION_HORZ].width_count = 0;
+ metrics->axis[AF_DIMENSION_VERT].width_count = 0;
+
+ {
+ FT_Error error;
+ FT_UInt glyph_index;
+ int dim;
+ AF_LatinMetricsRec dummy[1];
+ AF_Scaler scaler = &dummy->root.scaler;
+
+
+ glyph_index = FT_Get_Char_Index( face, charcode );
+ if ( glyph_index == 0 )
+ goto Exit;
+
+ error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
+ if ( error || face->glyph->outline.n_points <= 0 )
+ goto Exit;
+
+ FT_ZERO( dummy );
+
+ dummy->units_per_em = metrics->units_per_em;
+ scaler->x_scale = scaler->y_scale = 0x10000L;
+ scaler->x_delta = scaler->y_delta = 0;
+ scaler->face = face;
+ scaler->render_mode = FT_RENDER_MODE_NORMAL;
+ scaler->flags = 0;
+
+ af_glyph_hints_rescale( hints, (AF_ScriptMetrics)dummy );
+
+ error = af_glyph_hints_reload( hints, &face->glyph->outline, 0 );
+ if ( error )
+ goto Exit;
+
+ for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
+ {
+ AF_LatinAxis axis = &metrics->axis[dim];
+ AF_AxisHints axhints = &hints->axis[dim];
+ AF_Segment seg, limit, link;
+ FT_UInt num_widths = 0;
+
+
+ error = af_latin_hints_compute_segments( hints,
+ (AF_Dimension)dim );
+ if ( error )
+ goto Exit;
+
+ af_latin_hints_link_segments( hints,
+ (AF_Dimension)dim );
+
+ seg = axhints->segments;
+ limit = seg + axhints->num_segments;
+
+ for ( ; seg < limit; seg++ )
+ {
+ link = seg->link;
+
+ /* we only consider stem segments there! */
+ if ( link && link->link == seg && link > seg )
+ {
+ FT_Pos dist;
+
+
+ dist = seg->pos - link->pos;
+ if ( dist < 0 )
+ dist = -dist;
+
+ if ( num_widths < AF_LATIN_MAX_WIDTHS )
+ axis->widths[ num_widths++ ].org = dist;
+ }
+ }
+
+ af_sort_widths( num_widths, axis->widths );
+ axis->width_count = num_widths;
+ }
+
+ Exit:
+ for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
+ {
+ AF_LatinAxis axis = &metrics->axis[dim];
+ FT_Pos stdw;
+
+
+ stdw = ( axis->width_count > 0 )
+ ? axis->widths[0].org
+ : AF_LATIN_CONSTANT( metrics, 50 );
+
+ /* let's try 20% of the smallest width */
+ axis->edge_distance_threshold = stdw / 5;
+ axis->standard_width = stdw;
+ axis->extra_light = 0;
+ }
+ }
+
+ af_glyph_hints_done( hints );
+ }
+
+
+
+#define AF_LATIN_MAX_TEST_CHARACTERS 12
+
+
+ static const char* const af_latin_blue_chars[AF_LATIN_MAX_BLUES] =
+ {
+ "THEZOCQS",
+ "HEZLOCUS",
+ "fijkdbh",
+ "xzroesc",
+ "xzroesc",
+ "pqgjy"
+ };
+
+
+ static void
+ af_latin_metrics_init_blues( AF_LatinMetrics metrics,
+ FT_Face face )
+ {
+ FT_Pos flats [AF_LATIN_MAX_TEST_CHARACTERS];
+ FT_Pos rounds[AF_LATIN_MAX_TEST_CHARACTERS];
+ FT_Int num_flats;
+ FT_Int num_rounds;
+ FT_Int bb;
+ AF_LatinBlue blue;
+ FT_Error error;
+ AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT];
+ FT_GlyphSlot glyph = face->glyph;
+
+
+ /* we compute the blues simply by loading each character from the */
+ /* 'af_latin_blue_chars[blues]' string, then compute its top-most or */
+ /* bottom-most points (depending on `AF_IS_TOP_BLUE') */
+
+ AF_LOG(( "blue zones computation\n" ));
+ AF_LOG(( "------------------------------------------------\n" ));
+
+ for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ )
+ {
+ const char* p = af_latin_blue_chars[bb];
+ const char* limit = p + AF_LATIN_MAX_TEST_CHARACTERS;
+ FT_Pos* blue_ref;
+ FT_Pos* blue_shoot;
+
+
+ AF_LOG(( "blue %3d: ", bb ));
+
+ num_flats = 0;
+ num_rounds = 0;
+
+ for ( ; p < limit && *p; p++ )
+ {
+ FT_UInt glyph_index;
+ FT_Int best_point, best_y, best_first, best_last;
+ FT_Vector* points;
+ FT_Bool round = 0;
+
+
+ AF_LOG(( "'%c'", *p ));
+
+ /* load the character in the face -- skip unknown or empty ones */
+ glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p );
+ if ( glyph_index == 0 )
+ continue;
+
+ error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
+ if ( error || glyph->outline.n_points <= 0 )
+ continue;
+
+ /* now compute min or max point indices and coordinates */
+ points = glyph->outline.points;
+ best_point = -1;
+ best_y = 0; /* make compiler happy */
+ best_first = 0; /* ditto */
+ best_last = 0; /* ditto */
+
+ {
+ FT_Int nn;
+ FT_Int first = 0;
+ FT_Int last = -1;
+
+
+ for ( nn = 0; nn < glyph->outline.n_contours; first = last+1, nn++ )
+ {
+ FT_Int old_best_point = best_point;
+ FT_Int pp;
+
+
+ last = glyph->outline.contours[nn];
+
+ /* Avoid single-point contours since they are never rasterized. */
+ /* In some fonts, they correspond to mark attachment points */
+ /* which are way outside of the glyph's real outline. */
+ if ( last <= first )
+ continue;
+
+ if ( AF_LATIN_IS_TOP_BLUE( bb ) )
+ {
+ for ( pp = first; pp <= last; pp++ )
+ if ( best_point < 0 || points[pp].y > best_y )
+ {
+ best_point = pp;
+ best_y = points[pp].y;
+ }
+ }
+ else
+ {
+ for ( pp = first; pp <= last; pp++ )
+ if ( best_point < 0 || points[pp].y < best_y )
+ {
+ best_point = pp;
+ best_y = points[pp].y;
+ }
+ }
+
+ if ( best_point != old_best_point )
+ {
+ best_first = first;
+ best_last = last;
+ }
+ }
+ AF_LOG(( "%5d", best_y ));
+ }
+
+ /* now check whether the point belongs to a straight or round */
+ /* segment; we first need to find in which contour the extremum */
+ /* lies, then inspect its previous and next points */
+ if ( best_point >= 0 )
+ {
+ FT_Int prev, next;
+ FT_Pos dist;
+
+
+ /* now look for the previous and next points that are not on the */
+ /* same Y coordinate. Threshold the `closeness'... */
+ prev = best_point;
+ next = prev;
+
+ do
+ {
+ if ( prev > best_first )
+ prev--;
+ else
+ prev = best_last;
+
+ dist = points[prev].y - best_y;
+ if ( dist < -5 || dist > 5 )
+ break;
+
+ } while ( prev != best_point );
+
+ do
+ {
+ if ( next < best_last )
+ next++;
+ else
+ next = best_first;
+
+ dist = points[next].y - best_y;
+ if ( dist < -5 || dist > 5 )
+ break;
+
+ } while ( next != best_point );
+
+ /* now, set the `round' flag depending on the segment's kind */
+ round = FT_BOOL(
+ FT_CURVE_TAG( glyph->outline.tags[prev] ) != FT_CURVE_TAG_ON ||
+ FT_CURVE_TAG( glyph->outline.tags[next] ) != FT_CURVE_TAG_ON );
+
+ AF_LOG(( "%c ", round ? 'r' : 'f' ));
+ }
+
+ if ( round )
+ rounds[num_rounds++] = best_y;
+ else
+ flats[num_flats++] = best_y;
+ }
+
+ AF_LOG(( "\n" ));
+
+ if ( num_flats == 0 && num_rounds == 0 )
+ {
+ /*
+ * we couldn't find a single glyph to compute this blue zone,
+ * we will simply ignore it then
+ */
+ AF_LOG(( "empty!\n" ));
+ continue;
+ }
+
+ /* we have computed the contents of the `rounds' and `flats' tables, */
+ /* now determine the reference and overshoot position of the blue -- */
+ /* we simply take the median value after a simple sort */
+ af_sort_pos( num_rounds, rounds );
+ af_sort_pos( num_flats, flats );
+
+ blue = & axis->blues[axis->blue_count];
+ blue_ref = & blue->ref.org;
+ blue_shoot = & blue->shoot.org;
+
+ axis->blue_count++;
+
+ if ( num_flats == 0 )
+ {
+ *blue_ref =
+ *blue_shoot = rounds[num_rounds / 2];
+ }
+ else if ( num_rounds == 0 )
+ {
+ *blue_ref =
+ *blue_shoot = flats[num_flats / 2];
+ }
+ else
+ {
+ *blue_ref = flats[num_flats / 2];
+ *blue_shoot = rounds[num_rounds / 2];
+ }
+
+ /* there are sometimes problems: if the overshoot position of top */
+ /* zones is under its reference position, or the opposite for bottom */
+ /* zones. We must thus check everything there and correct the errors */
+ if ( *blue_shoot != *blue_ref )
+ {
+ FT_Pos ref = *blue_ref;
+ FT_Pos shoot = *blue_shoot;
+ FT_Bool over_ref = FT_BOOL( shoot > ref );
+
+
+ if ( AF_LATIN_IS_TOP_BLUE( bb ) ^ over_ref )
+ *blue_shoot = *blue_ref = ( shoot + ref ) / 2;
+ }
+
+ blue->flags = 0;
+ if ( AF_LATIN_IS_TOP_BLUE( bb ) )
+ blue->flags |= AF_LATIN_BLUE_TOP;
+
+ /*
+ * The following flags is used later to adjust the y and x scales
+ * in order to optimize the pixel grid alignment of the top of small
+ * letters.
+ */
+ if ( bb == AF_LATIN_BLUE_SMALL_TOP )
+ blue->flags |= AF_LATIN_BLUE_ADJUSTMENT;
+
+ AF_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot ));
+ }
+
+ return;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ af_latin_metrics_init( AF_LatinMetrics metrics,
+ FT_Face face )
+ {
+ FT_Error error = AF_Err_Ok;
+ FT_CharMap oldmap = face->charmap;
+ FT_UInt ee;
+
+ static const FT_Encoding latin_encodings[] =
+ {
+ FT_ENCODING_UNICODE,
+ FT_ENCODING_APPLE_ROMAN,
+ FT_ENCODING_ADOBE_STANDARD,
+ FT_ENCODING_ADOBE_LATIN_1,
+ FT_ENCODING_NONE /* end of list */
+ };
+
+
+ metrics->units_per_em = face->units_per_EM;
+
+ /* do we have a latin charmap in there? */
+ for ( ee = 0; latin_encodings[ee] != FT_ENCODING_NONE; ee++ )
+ {
+ error = FT_Select_Charmap( face, latin_encodings[ee] );
+ if ( !error )
+ break;
+ }
+
+ if ( !error )
+ {
+ /* For now, compute the standard width and height from the `o'. */
+ af_latin_metrics_init_widths( metrics, face, 'o' );
+ af_latin_metrics_init_blues( metrics, face );
+ }
+
+ FT_Set_Charmap( face, oldmap );
+ return AF_Err_Ok;
+ }
+
+
+ static void
+ af_latin_metrics_scale_dim( AF_LatinMetrics metrics,
+ AF_Scaler scaler,
+ AF_Dimension dim )
+ {
+ FT_Fixed scale;
+ FT_Pos delta;
+ AF_LatinAxis axis;
+ FT_UInt nn;
+
+
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ scale = scaler->x_scale;
+ delta = scaler->x_delta;
+ }
+ else
+ {
+ scale = scaler->y_scale;
+ delta = scaler->y_delta;
+ }
+
+ axis = &metrics->axis[dim];
+
+ if ( axis->org_scale == scale && axis->org_delta == delta )
+ return;
+
+ axis->org_scale = scale;
+ axis->org_delta = delta;
+
+ /*
+ * correct X and Y scale to optimize the alignment of the top of small
+ * letters to the pixel grid
+ */
+ {
+ AF_LatinAxis Axis = &metrics->axis[AF_DIMENSION_VERT];
+ AF_LatinBlue blue = NULL;
+
+
+ for ( nn = 0; nn < Axis->blue_count; nn++ )
+ {
+ if ( Axis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT )
+ {
+ blue = &Axis->blues[nn];
+ break;
+ }
+ }
+
+ if ( blue )
+ {
+ FT_Pos scaled = FT_MulFix( blue->shoot.org, scaler->y_scale );
+ FT_Pos fitted = ( scaled + 40 ) & ~63;
+
+
+ if ( scaled != fitted )
+ {
+#if 0
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ if ( fitted < scaled )
+ scale -= scale / 50; /* scale *= 0.98 */
+ }
+ else
+#endif
+ if ( dim == AF_DIMENSION_VERT )
+ {
+ scale = FT_MulDiv( scale, fitted, scaled );
+ }
+ }
+ }
+ }
+
+ axis->scale = scale;
+ axis->delta = delta;
+
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ metrics->root.scaler.x_scale = scale;
+ metrics->root.scaler.x_delta = delta;
+ }
+ else
+ {
+ metrics->root.scaler.y_scale = scale;
+ metrics->root.scaler.y_delta = delta;
+ }
+
+ /* scale the standard widths */
+ for ( nn = 0; nn < axis->width_count; nn++ )
+ {
+ AF_Width width = axis->widths + nn;
+
+
+ width->cur = FT_MulFix( width->org, scale );
+ width->fit = width->cur;
+ }
+
+ /* an extra-light axis corresponds to a standard width that is */
+ /* smaller than 0.75 pixels */
+ axis->extra_light =
+ (FT_Bool)( FT_MulFix( axis->standard_width, scale ) < 32 + 8 );
+
+ if ( dim == AF_DIMENSION_VERT )
+ {
+ /* scale the blue zones */
+ for ( nn = 0; nn < axis->blue_count; nn++ )
+ {
+ AF_LatinBlue blue = &axis->blues[nn];
+ FT_Pos dist;
+
+
+ blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta;
+ blue->ref.fit = blue->ref.cur;
+ blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta;
+ blue->shoot.fit = blue->shoot.cur;
+ blue->flags &= ~AF_LATIN_BLUE_ACTIVE;
+
+ /* a blue zone is only active if it is less than 3/4 pixels tall */
+ dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
+ if ( dist <= 48 && dist >= -48 )
+ {
+ FT_Pos delta1, delta2;
+
+
+ delta1 = blue->shoot.org - blue->ref.org;
+ delta2 = delta1;
+ if ( delta1 < 0 )
+ delta2 = -delta2;
+
+ delta2 = FT_MulFix( delta2, scale );
+
+ if ( delta2 < 32 )
+ delta2 = 0;
+ else if ( delta2 < 64 )
+ delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 );
+ else
+ delta2 = FT_PIX_ROUND( delta2 );
+
+ if ( delta1 < 0 )
+ delta2 = -delta2;
+
+ blue->ref.fit = FT_PIX_ROUND( blue->ref.cur );
+ blue->shoot.fit = blue->ref.fit + delta2;
+
+ blue->flags |= AF_LATIN_BLUE_ACTIVE;
+ }
+ }
+ }
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_latin_metrics_scale( AF_LatinMetrics metrics,
+ AF_Scaler scaler )
+ {
+ metrics->root.scaler.render_mode = scaler->render_mode;
+ metrics->root.scaler.face = scaler->face;
+
+ af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ );
+ af_latin_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** L A T I N G L Y P H A N A L Y S I S *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_LOCAL_DEF( FT_Error )
+ af_latin_hints_compute_segments( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_AxisHints axis = &hints->axis[dim];
+ FT_Memory memory = hints->memory;
+ FT_Error error = AF_Err_Ok;
+ AF_Segment segment = NULL;
+ AF_SegmentRec seg0;
+ AF_Point* contour = hints->contours;
+ AF_Point* contour_limit = contour + hints->num_contours;
+ AF_Direction major_dir, segment_dir;
+
+
+ FT_ZERO( &seg0 );
+ seg0.score = 32000;
+ seg0.flags = AF_EDGE_NORMAL;
+
+ major_dir = (AF_Direction)FT_ABS( axis->major_dir );
+ segment_dir = major_dir;
+
+ axis->num_segments = 0;
+
+ /* set up (u,v) in each point */
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ AF_Point point = hints->points;
+ AF_Point limit = point + hints->num_points;
+
+
+ for ( ; point < limit; point++ )
+ {
+ point->u = point->fx;
+ point->v = point->fy;
+ }
+ }
+ else
+ {
+ AF_Point point = hints->points;
+ AF_Point limit = point + hints->num_points;
+
+
+ for ( ; point < limit; point++ )
+ {
+ point->u = point->fy;
+ point->v = point->fx;
+ }
+ }
+
+ /* do each contour separately */
+ for ( ; contour < contour_limit; contour++ )
+ {
+ AF_Point point = contour[0];
+ AF_Point last = point->prev;
+ int on_edge = 0;
+ FT_Pos min_pos = 32000; /* minimum segment pos != min_coord */
+ FT_Pos max_pos = -32000; /* maximum segment pos != max_coord */
+ FT_Bool passed;
+
+
+ if ( point == last ) /* skip singletons -- just in case */
+ continue;
+
+ if ( FT_ABS( last->out_dir ) == major_dir &&
+ FT_ABS( point->out_dir ) == major_dir )
+ {
+ /* we are already on an edge, try to locate its start */
+ last = point;
+
+ for (;;)
+ {
+ point = point->prev;
+ if ( FT_ABS( point->out_dir ) != major_dir )
+ {
+ point = point->next;
+ break;
+ }
+ if ( point == last )
+ break;
+ }
+ }
+
+ last = point;
+ passed = 0;
+
+ for (;;)
+ {
+ FT_Pos u, v;
+
+
+ if ( on_edge )
+ {
+ u = point->u;
+ if ( u < min_pos )
+ min_pos = u;
+ if ( u > max_pos )
+ max_pos = u;
+
+ if ( point->out_dir != segment_dir || point == last )
+ {
+ /* we are just leaving an edge; record a new segment! */
+ segment->last = point;
+ segment->pos = (FT_Short)( ( min_pos + max_pos ) >> 1 );
+
+ /* a segment is round if either its first or last point */
+ /* is a control point */
+ if ( ( segment->first->flags | point->flags ) &
+ AF_FLAG_CONTROL )
+ segment->flags |= AF_EDGE_ROUND;
+
+ /* compute segment size */
+ min_pos = max_pos = point->v;
+
+ v = segment->first->v;
+ if ( v < min_pos )
+ min_pos = v;
+ if ( v > max_pos )
+ max_pos = v;
+
+ segment->min_coord = (FT_Short)min_pos;
+ segment->max_coord = (FT_Short)max_pos;
+ segment->height = (FT_Short)( segment->max_coord -
+ segment->min_coord );
+
+ on_edge = 0;
+ segment = NULL;
+ /* fallthrough */
+ }
+ }
+
+ /* now exit if we are at the start/end point */
+ if ( point == last )
+ {
+ if ( passed )
+ break;
+ passed = 1;
+ }
+
+ if ( !on_edge && FT_ABS( point->out_dir ) == major_dir )
+ {
+ /* this is the start of a new segment! */
+ segment_dir = (AF_Direction)point->out_dir;
+
+ /* clear all segment fields */
+ error = af_axis_hints_new_segment( axis, memory, &segment );
+ if ( error )
+ goto Exit;
+
+ segment[0] = seg0;
+ segment->dir = (FT_Char)segment_dir;
+ min_pos = max_pos = point->u;
+ segment->first = point;
+ segment->last = point;
+ segment->contour = contour;
+ on_edge = 1;
+ }
+
+ point = point->next;
+ }
+
+ } /* contours */
+
+
+ /* now slightly increase the height of segments when this makes */
+ /* sense -- this is used to better detect and ignore serifs */
+ {
+ AF_Segment segments = axis->segments;
+ AF_Segment segments_end = segments + axis->num_segments;
+
+
+ for ( segment = segments; segment < segments_end; segment++ )
+ {
+ AF_Point first = segment->first;
+ AF_Point last = segment->last;
+ FT_Pos first_v = first->v;
+ FT_Pos last_v = last->v;
+
+
+ if ( first == last )
+ continue;
+
+ if ( first_v < last_v )
+ {
+ AF_Point p;
+
+
+ p = first->prev;
+ if ( p->v < first_v )
+ segment->height = (FT_Short)( segment->height +
+ ( ( first_v - p->v ) >> 1 ) );
+
+ p = last->next;
+ if ( p->v > last_v )
+ segment->height = (FT_Short)( segment->height +
+ ( ( p->v - last_v ) >> 1 ) );
+ }
+ else
+ {
+ AF_Point p;
+
+
+ p = first->prev;
+ if ( p->v > first_v )
+ segment->height = (FT_Short)( segment->height +
+ ( ( p->v - first_v ) >> 1 ) );
+
+ p = last->next;
+ if ( p->v < last_v )
+ segment->height = (FT_Short)( segment->height +
+ ( ( last_v - p->v ) >> 1 ) );
+ }
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_latin_hints_link_segments( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_AxisHints axis = &hints->axis[dim];
+ AF_Segment segments = axis->segments;
+ AF_Segment segment_limit = segments + axis->num_segments;
+ FT_Pos len_threshold, len_score;
+ AF_Segment seg1, seg2;
+
+
+ len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 );
+ if ( len_threshold == 0 )
+ len_threshold = 1;
+
+ len_score = AF_LATIN_CONSTANT( hints->metrics, 6000 );
+
+ /* now compare each segment to the others */
+ for ( seg1 = segments; seg1 < segment_limit; seg1++ )
+ {
+ /* the fake segments are introduced to hint the metrics -- */
+ /* we must never link them to anything */
+ if ( seg1->dir != axis->major_dir || seg1->first == seg1->last )
+ continue;
+
+ for ( seg2 = segments; seg2 < segment_limit; seg2++ )
+ if ( seg1->dir + seg2->dir == 0 && seg2->pos > seg1->pos )
+ {
+ FT_Pos pos1 = seg1->pos;
+ FT_Pos pos2 = seg2->pos;
+ FT_Pos dist = pos2 - pos1;
+
+
+ if ( dist < 0 )
+ dist = -dist;
+
+ {
+ FT_Pos min = seg1->min_coord;
+ FT_Pos max = seg1->max_coord;
+ FT_Pos len, score;
+
+
+ if ( min < seg2->min_coord )
+ min = seg2->min_coord;
+
+ if ( max > seg2->max_coord )
+ max = seg2->max_coord;
+
+ len = max - min;
+ if ( len >= len_threshold )
+ {
+ score = dist + len_score / len;
+
+ if ( score < seg1->score )
+ {
+ seg1->score = score;
+ seg1->link = seg2;
+ }
+
+ if ( score < seg2->score )
+ {
+ seg2->score = score;
+ seg2->link = seg1;
+ }
+ }
+ }
+ }
+ }
+
+ /* now, compute the `serif' segments */
+ for ( seg1 = segments; seg1 < segment_limit; seg1++ )
+ {
+ seg2 = seg1->link;
+
+ if ( seg2 )
+ {
+ if ( seg2->link != seg1 )
+ {
+ seg1->link = 0;
+ seg1->serif = seg2->link;
+ }
+ }
+ }
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ af_latin_hints_compute_edges( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_AxisHints axis = &hints->axis[dim];
+ FT_Error error = AF_Err_Ok;
+ FT_Memory memory = hints->memory;
+ AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim];
+
+ AF_Segment segments = axis->segments;
+ AF_Segment segment_limit = segments + axis->num_segments;
+ AF_Segment seg;
+
+ AF_Direction up_dir;
+ FT_Fixed scale;
+ FT_Pos edge_distance_threshold;
+ FT_Pos segment_length_threshold;
+
+
+ axis->num_edges = 0;
+
+ scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
+ : hints->y_scale;
+
+ up_dir = ( dim == AF_DIMENSION_HORZ ) ? AF_DIR_UP
+ : AF_DIR_RIGHT;
+
+ /*
+ * We ignore all segments that are less than 1 pixels in length,
+ * to avoid many problems with serif fonts. We compute the
+ * corresponding threshold in font units.
+ */
+ if ( dim == AF_DIMENSION_HORZ )
+ segment_length_threshold = FT_DivFix( 64, hints->y_scale );
+ else
+ segment_length_threshold = 0;
+
+ /*********************************************************************/
+ /* */
+ /* We will begin by generating a sorted table of edges for the */
+ /* current direction. To do so, we simply scan each segment and try */
+ /* to find an edge in our table that corresponds to its position. */
+ /* */
+ /* If no edge is found, we create and insert a new edge in the */
+ /* sorted table. Otherwise, we simply add the segment to the edge's */
+ /* list which will be processed in the second step to compute the */
+ /* edge's properties. */
+ /* */
+ /* Note that the edges table is sorted along the segment/edge */
+ /* position. */
+ /* */
+ /*********************************************************************/
+
+ edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
+ scale );
+ if ( edge_distance_threshold > 64 / 4 )
+ edge_distance_threshold = 64 / 4;
+
+ edge_distance_threshold = FT_DivFix( edge_distance_threshold,
+ scale );
+
+ for ( seg = segments; seg < segment_limit; seg++ )
+ {
+ AF_Edge found = 0;
+ FT_Int ee;
+
+
+ if ( seg->height < segment_length_threshold )
+ continue;
+
+ /* A special case for serif edges: If they are smaller than */
+ /* 1.5 pixels we ignore them. */
+ if ( seg->serif &&
+ 2 * seg->height < 3 * segment_length_threshold )
+ continue;
+
+ /* look for an edge corresponding to the segment */
+ for ( ee = 0; ee < axis->num_edges; ee++ )
+ {
+ AF_Edge edge = axis->edges + ee;
+ FT_Pos dist;
+
+
+ dist = seg->pos - edge->fpos;
+ if ( dist < 0 )
+ dist = -dist;
+
+ if ( dist < edge_distance_threshold && edge->dir == seg->dir )
+ {
+ found = edge;
+ break;
+ }
+ }
+
+ if ( !found )
+ {
+ AF_Edge edge;
+
+
+ /* insert a new edge in the list and */
+ /* sort according to the position */
+ error = af_axis_hints_new_edge( axis, seg->pos,
+ (AF_Direction)seg->dir,
+ memory, &edge );
+ if ( error )
+ goto Exit;
+
+ /* add the segment to the new edge's list */
+ FT_ZERO( edge );
+
+ edge->first = seg;
+ edge->last = seg;
+ edge->fpos = seg->pos;
+ edge->dir = seg->dir;
+ edge->opos = edge->pos = FT_MulFix( seg->pos, scale );
+ seg->edge_next = seg;
+ }
+ else
+ {
+ /* if an edge was found, simply add the segment to the edge's */
+ /* list */
+ seg->edge_next = found->first;
+ found->last->edge_next = seg;
+ found->last = seg;
+ }
+ }
+
+
+ /*********************************************************************/
+ /* */
+ /* Good, we will now compute each edge's properties according to */
+ /* segments found on its position. Basically, these are: */
+ /* */
+ /* - edge's main direction */
+ /* - stem edge, serif edge or both (which defaults to stem then) */
+ /* - rounded edge, straight or both (which defaults to straight) */
+ /* - link for edge */
+ /* */
+ /*********************************************************************/
+
+ /* first of all, set the `edge' field in each segment -- this is */
+ /* required in order to compute edge links */
+
+ /*
+ * Note that removing this loop and setting the `edge' field of each
+ * segment directly in the code above slows down execution speed for
+ * some reasons on platforms like the Sun.
+ */
+ {
+ AF_Edge edges = axis->edges;
+ AF_Edge edge_limit = edges + axis->num_edges;
+ AF_Edge edge;
+
+
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ seg = edge->first;
+ if ( seg )
+ do
+ {
+ seg->edge = edge;
+ seg = seg->edge_next;
+
+ } while ( seg != edge->first );
+ }
+
+ /* now, compute each edge properties */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ FT_Int is_round = 0; /* does it contain round segments? */
+ FT_Int is_straight = 0; /* does it contain straight segments? */
+ FT_Pos ups = 0; /* number of upwards segments */
+ FT_Pos downs = 0; /* number of downwards segments */
+
+
+ seg = edge->first;
+
+ do
+ {
+ FT_Bool is_serif;
+
+
+ /* check for roundness of segment */
+ if ( seg->flags & AF_EDGE_ROUND )
+ is_round++;
+ else
+ is_straight++;
+
+ /* check for segment direction */
+ if ( seg->dir == up_dir )
+ ups += seg->max_coord-seg->min_coord;
+ else
+ downs += seg->max_coord-seg->min_coord;
+
+ /* check for links -- if seg->serif is set, then seg->link must */
+ /* be ignored */
+ is_serif = (FT_Bool)( seg->serif &&
+ seg->serif->edge &&
+ seg->serif->edge != edge );
+
+ if ( ( seg->link && seg->link->edge != NULL ) || is_serif )
+ {
+ AF_Edge edge2;
+ AF_Segment seg2;
+
+
+ edge2 = edge->link;
+ seg2 = seg->link;
+
+ if ( is_serif )
+ {
+ seg2 = seg->serif;
+ edge2 = edge->serif;
+ }
+
+ if ( edge2 )
+ {
+ FT_Pos edge_delta;
+ FT_Pos seg_delta;
+
+
+ edge_delta = edge->fpos - edge2->fpos;
+ if ( edge_delta < 0 )
+ edge_delta = -edge_delta;
+
+ seg_delta = seg->pos - seg2->pos;
+ if ( seg_delta < 0 )
+ seg_delta = -seg_delta;
+
+ if ( seg_delta < edge_delta )
+ edge2 = seg2->edge;
+ }
+ else
+ edge2 = seg2->edge;
+
+ if ( is_serif )
+ {
+ edge->serif = edge2;
+ edge2->flags |= AF_EDGE_SERIF;
+ }
+ else
+ edge->link = edge2;
+ }
+
+ seg = seg->edge_next;
+
+ } while ( seg != edge->first );
+
+ /* set the round/straight flags */
+ edge->flags = AF_EDGE_NORMAL;
+
+ if ( is_round > 0 && is_round >= is_straight )
+ edge->flags |= AF_EDGE_ROUND;
+
+#if 0
+ /* set the edge's main direction */
+ edge->dir = AF_DIR_NONE;
+
+ if ( ups > downs )
+ edge->dir = (FT_Char)up_dir;
+
+ else if ( ups < downs )
+ edge->dir = (FT_Char)-up_dir;
+
+ else if ( ups == downs )
+ edge->dir = 0; /* both up and down! */
+#endif
+
+ /* gets rid of serifs if link is set */
+ /* XXX: This gets rid of many unpleasant artefacts! */
+ /* Example: the `c' in cour.pfa at size 13 */
+
+ if ( edge->serif && edge->link )
+ edge->serif = 0;
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ af_latin_hints_detect_features( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ FT_Error error;
+
+
+ error = af_latin_hints_compute_segments( hints, dim );
+ if ( !error )
+ {
+ af_latin_hints_link_segments( hints, dim );
+
+ error = af_latin_hints_compute_edges( hints, dim );
+ }
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_latin_hints_compute_blue_edges( AF_GlyphHints hints,
+ AF_LatinMetrics metrics )
+ {
+ AF_AxisHints axis = &hints->axis[ AF_DIMENSION_VERT ];
+ AF_Edge edge = axis->edges;
+ AF_Edge edge_limit = edge + axis->num_edges;
+ AF_LatinAxis latin = &metrics->axis[ AF_DIMENSION_VERT ];
+ FT_Fixed scale = latin->scale;
+
+
+ /* compute which blue zones are active, i.e. have their scaled */
+ /* size < 3/4 pixels */
+
+ /* for each horizontal edge search the blue zone which is closest */
+ for ( ; edge < edge_limit; edge++ )
+ {
+ FT_Int bb;
+ AF_Width best_blue = NULL;
+ FT_Pos best_dist; /* initial threshold */
+
+
+ /* compute the initial threshold as a fraction of the EM size */
+ best_dist = FT_MulFix( metrics->units_per_em / 40, scale );
+
+ if ( best_dist > 64 / 2 )
+ best_dist = 64 / 2;
+
+ for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ )
+ {
+ AF_LatinBlue blue = latin->blues + bb;
+ FT_Bool is_top_blue, is_major_dir;
+
+
+ /* skip inactive blue zones (i.e., those that are too small) */
+ if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) )
+ continue;
+
+ /* if it is a top zone, check for right edges -- if it is a bottom */
+ /* zone, check for left edges */
+ /* */
+ /* of course, that's for TrueType */
+ is_top_blue = (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_TOP ) != 0 );
+ is_major_dir = FT_BOOL( edge->dir == axis->major_dir );
+
+ /* if it is a top zone, the edge must be against the major */
+ /* direction; if it is a bottom zone, it must be in the major */
+ /* direction */
+ if ( is_top_blue ^ is_major_dir )
+ {
+ FT_Pos dist;
+
+
+ /* first of all, compare it to the reference position */
+ dist = edge->fpos - blue->ref.org;
+ if ( dist < 0 )
+ dist = -dist;
+
+ dist = FT_MulFix( dist, scale );
+ if ( dist < best_dist )
+ {
+ best_dist = dist;
+ best_blue = & blue->ref;
+ }
+
+ /* now, compare it to the overshoot position if the edge is */
+ /* rounded, and if the edge is over the reference position of a */
+ /* top zone, or under the reference position of a bottom zone */
+ if ( edge->flags & AF_EDGE_ROUND && dist != 0 )
+ {
+ FT_Bool is_under_ref = FT_BOOL( edge->fpos < blue->ref.org );
+
+
+ if ( is_top_blue ^ is_under_ref )
+ {
+ blue = latin->blues + bb;
+ dist = edge->fpos - blue->shoot.org;
+ if ( dist < 0 )
+ dist = -dist;
+
+ dist = FT_MulFix( dist, scale );
+ if ( dist < best_dist )
+ {
+ best_dist = dist;
+ best_blue = & blue->shoot;
+ }
+ }
+ }
+ }
+ }
+
+ if ( best_blue )
+ edge->blue_edge = best_blue;
+ }
+ }
+
+
+ static FT_Error
+ af_latin_hints_init( AF_GlyphHints hints,
+ AF_LatinMetrics metrics )
+ {
+ FT_Render_Mode mode;
+ FT_UInt32 scaler_flags, other_flags;
+ FT_Face face = metrics->root.scaler.face;
+
+
+ af_glyph_hints_rescale( hints, (AF_ScriptMetrics)metrics );
+
+ /*
+ * correct x_scale and y_scale if needed, since they may have
+ * been modified `af_latin_metrics_scale_dim' above
+ */
+ hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale;
+ hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta;
+ hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale;
+ hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta;
+
+ /* compute flags depending on render mode, etc. */
+ mode = metrics->root.scaler.render_mode;
+
+#if 0 /* #ifdef AF_USE_WARPER */
+ if ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V )
+ {
+ metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL;
+ }
+#endif
+
+ scaler_flags = hints->scaler_flags;
+ other_flags = 0;
+
+ /*
+ * We snap the width of vertical stems for the monochrome and
+ * horizontal LCD rendering targets only.
+ */
+ if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD )
+ other_flags |= AF_LATIN_HINTS_HORZ_SNAP;
+
+ /*
+ * We snap the width of horizontal stems for the monochrome and
+ * vertical LCD rendering targets only.
+ */
+ if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V )
+ other_flags |= AF_LATIN_HINTS_VERT_SNAP;
+
+ /*
+ * We adjust stems to full pixels only if we don't use the `light' mode.
+ */
+ if ( mode != FT_RENDER_MODE_LIGHT )
+ other_flags |= AF_LATIN_HINTS_STEM_ADJUST;
+
+ if ( mode == FT_RENDER_MODE_MONO )
+ other_flags |= AF_LATIN_HINTS_MONO;
+
+ /*
+ * In `light' hinting mode we disable horizontal hinting completely.
+ * We also do it if the face is italic.
+ */
+ if ( mode == FT_RENDER_MODE_LIGHT ||
+ (face->style_flags & FT_STYLE_FLAG_ITALIC) != 0 )
+ scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL;
+
+ hints->scaler_flags = scaler_flags;
+ hints->other_flags = other_flags;
+
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** L A T I N G L Y P H G R I D - F I T T I N G *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* snap a given width in scaled coordinates to one of the */
+ /* current standard widths */
+
+ static FT_Pos
+ af_latin_snap_width( AF_Width widths,
+ FT_Int count,
+ FT_Pos width )
+ {
+ int n;
+ FT_Pos best = 64 + 32 + 2;
+ FT_Pos reference = width;
+ FT_Pos scaled;
+
+
+ for ( n = 0; n < count; n++ )
+ {
+ FT_Pos w;
+ FT_Pos dist;
+
+
+ w = widths[n].cur;
+ dist = width - w;
+ if ( dist < 0 )
+ dist = -dist;
+ if ( dist < best )
+ {
+ best = dist;
+ reference = w;
+ }
+ }
+
+ scaled = FT_PIX_ROUND( reference );
+
+ if ( width >= reference )
+ {
+ if ( width < scaled + 48 )
+ width = reference;
+ }
+ else
+ {
+ if ( width > scaled - 48 )
+ width = reference;
+ }
+
+ return width;
+ }
+
+
+ /* compute the snapped width of a given stem */
+
+ static FT_Pos
+ af_latin_compute_stem_width( AF_GlyphHints hints,
+ AF_Dimension dim,
+ FT_Pos width,
+ AF_Edge_Flags base_flags,
+ AF_Edge_Flags stem_flags )
+ {
+ AF_LatinMetrics metrics = (AF_LatinMetrics) hints->metrics;
+ AF_LatinAxis axis = & metrics->axis[dim];
+ FT_Pos dist = width;
+ FT_Int sign = 0;
+ FT_Int vertical = ( dim == AF_DIMENSION_VERT );
+
+
+ if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ||
+ axis->extra_light )
+ return width;
+
+ if ( dist < 0 )
+ {
+ dist = -width;
+ sign = 1;
+ }
+
+ if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
+ ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
+ {
+ /* smooth hinting process: very lightly quantize the stem width */
+
+ /* leave the widths of serifs alone */
+
+ if ( ( stem_flags & AF_EDGE_SERIF ) && vertical && ( dist < 3 * 64 ) )
+ goto Done_Width;
+
+ else if ( ( base_flags & AF_EDGE_ROUND ) )
+ {
+ if ( dist < 80 )
+ dist = 64;
+ }
+ else if ( dist < 56 )
+ dist = 56;
+
+ if ( axis->width_count > 0 )
+ {
+ FT_Pos delta;
+
+
+ /* compare to standard width */
+ if ( axis->width_count > 0 )
+ {
+ delta = dist - axis->widths[0].cur;
+
+ if ( delta < 0 )
+ delta = -delta;
+
+ if ( delta < 40 )
+ {
+ dist = axis->widths[0].cur;
+ if ( dist < 48 )
+ dist = 48;
+
+ goto Done_Width;
+ }
+ }
+
+ if ( dist < 3 * 64 )
+ {
+ delta = dist & 63;
+ dist &= -64;
+
+ if ( delta < 10 )
+ dist += delta;
+
+ else if ( delta < 32 )
+ dist += 10;
+
+ else if ( delta < 54 )
+ dist += 54;
+
+ else
+ dist += delta;
+ }
+ else
+ dist = ( dist + 32 ) & ~63;
+ }
+ }
+ else
+ {
+ /* strong hinting process: snap the stem width to integer pixels */
+ FT_Pos org_dist = dist;
+
+
+ dist = af_latin_snap_width( axis->widths, axis->width_count, dist );
+
+ if ( vertical )
+ {
+ /* in the case of vertical hinting, always round */
+ /* the stem heights to integer pixels */
+
+ if ( dist >= 64 )
+ dist = ( dist + 16 ) & ~63;
+ else
+ dist = 64;
+ }
+ else
+ {
+ if ( AF_LATIN_HINTS_DO_MONO( hints ) )
+ {
+ /* monochrome horizontal hinting: snap widths to integer pixels */
+ /* with a different threshold */
+
+ if ( dist < 64 )
+ dist = 64;
+ else
+ dist = ( dist + 32 ) & ~63;
+ }
+ else
+ {
+ /* for horizontal anti-aliased hinting, we adopt a more subtle */
+ /* approach: we strengthen small stems, round stems whose size */
+ /* is between 1 and 2 pixels to an integer, otherwise nothing */
+
+ if ( dist < 48 )
+ dist = ( dist + 64 ) >> 1;
+
+ else if ( dist < 128 )
+ {
+ /* We only round to an integer width if the corresponding */
+ /* distortion is less than 1/4 pixel. Otherwise this */
+ /* makes everything worse since the diagonals, which are */
+ /* not hinted, appear a lot bolder or thinner than the */
+ /* vertical stems. */
+
+ FT_Int delta;
+
+
+ dist = ( dist + 22 ) & ~63;
+ delta = dist - org_dist;
+ if ( delta < 0 )
+ delta = -delta;
+
+ if (delta >= 16)
+ {
+ dist = org_dist;
+ if ( dist < 48 )
+ dist = ( dist + 64 ) >> 1;
+ }
+ }
+ else
+ /* round otherwise to prevent color fringes in LCD mode */
+ dist = ( dist + 32 ) & ~63;
+ }
+ }
+ }
+
+ Done_Width:
+ if ( sign )
+ dist = -dist;
+
+ return dist;
+ }
+
+
+ /* align one stem edge relative to the previous stem edge */
+
+ static void
+ af_latin_align_linked_edge( AF_GlyphHints hints,
+ AF_Dimension dim,
+ AF_Edge base_edge,
+ AF_Edge stem_edge )
+ {
+ FT_Pos dist = stem_edge->opos - base_edge->opos;
+
+ FT_Pos fitted_width = af_latin_compute_stem_width(
+ hints, dim, dist,
+ (AF_Edge_Flags)base_edge->flags,
+ (AF_Edge_Flags)stem_edge->flags );
+
+
+ stem_edge->pos = base_edge->pos + fitted_width;
+
+ AF_LOG(( "LINK: edge %d (opos=%.2f) linked to (%.2f), "
+ "dist was %.2f, now %.2f\n",
+ stem_edge-hints->axis[dim].edges, stem_edge->opos / 64.0,
+ stem_edge->pos / 64.0, dist / 64.0, fitted_width / 64.0 ));
+ }
+
+
+ static void
+ af_latin_align_serif_edge( AF_GlyphHints hints,
+ AF_Edge base,
+ AF_Edge serif )
+ {
+ FT_UNUSED( hints );
+
+ serif->pos = base->pos + (serif->opos - base->opos);
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** E D G E H I N T I N G ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_LOCAL_DEF( void )
+ af_latin_hint_edges( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_AxisHints axis = &hints->axis[dim];
+ AF_Edge edges = axis->edges;
+ AF_Edge edge_limit = edges + axis->num_edges;
+ FT_Int n_edges;
+ AF_Edge edge;
+ AF_Edge anchor = 0;
+ FT_Int has_serifs = 0;
+
+
+ /* we begin by aligning all stems relative to the blue zone */
+ /* if needed -- that's only for horizontal edges */
+
+ if ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_BLUES( hints ) )
+ {
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ AF_Width blue;
+ AF_Edge edge1, edge2;
+
+
+ if ( edge->flags & AF_EDGE_DONE )
+ continue;
+
+ blue = edge->blue_edge;
+ edge1 = NULL;
+ edge2 = edge->link;
+
+ if ( blue )
+ {
+ edge1 = edge;
+ }
+ else if ( edge2 && edge2->blue_edge )
+ {
+ blue = edge2->blue_edge;
+ edge1 = edge2;
+ edge2 = edge;
+ }
+
+ if ( !edge1 )
+ continue;
+
+ AF_LOG(( "BLUE: edge %d (opos=%.2f) snapped to (%.2f), "
+ "was (%.2f)\n",
+ edge1-edges, edge1->opos / 64.0, blue->fit / 64.0,
+ edge1->pos / 64.0 ));
+
+ edge1->pos = blue->fit;
+ edge1->flags |= AF_EDGE_DONE;
+
+ if ( edge2 && !edge2->blue_edge )
+ {
+ af_latin_align_linked_edge( hints, dim, edge1, edge2 );
+ edge2->flags |= AF_EDGE_DONE;
+ }
+
+ if ( !anchor )
+ anchor = edge;
+ }
+ }
+
+ /* now we will align all stem edges, trying to maintain the */
+ /* relative order of stems in the glyph */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ AF_Edge edge2;
+
+
+ if ( edge->flags & AF_EDGE_DONE )
+ continue;
+
+ /* skip all non-stem edges */
+ edge2 = edge->link;
+ if ( !edge2 )
+ {
+ has_serifs++;
+ continue;
+ }
+
+ /* now align the stem */
+
+ /* this should not happen, but it's better to be safe */
+ if ( edge2->blue_edge )
+ {
+ AF_LOG(( "ASSERTION FAILED for edge %d\n", edge2-edges ));
+
+ af_latin_align_linked_edge( hints, dim, edge2, edge );
+ edge->flags |= AF_EDGE_DONE;
+ continue;
+ }
+
+ if ( !anchor )
+ {
+ FT_Pos org_len, org_center, cur_len;
+ FT_Pos cur_pos1, error1, error2, u_off, d_off;
+
+
+ org_len = edge2->opos - edge->opos;
+ cur_len = af_latin_compute_stem_width(
+ hints, dim, org_len,
+ (AF_Edge_Flags)edge->flags,
+ (AF_Edge_Flags)edge2->flags );
+ if ( cur_len <= 64 )
+ u_off = d_off = 32;
+ else
+ {
+ u_off = 38;
+ d_off = 26;
+ }
+
+ if ( cur_len < 96 )
+ {
+ org_center = edge->opos + ( org_len >> 1 );
+
+ cur_pos1 = FT_PIX_ROUND( org_center );
+
+ error1 = org_center - ( cur_pos1 - u_off );
+ if ( error1 < 0 )
+ error1 = -error1;
+
+ error2 = org_center - ( cur_pos1 + d_off );
+ if ( error2 < 0 )
+ error2 = -error2;
+
+ if ( error1 < error2 )
+ cur_pos1 -= u_off;
+ else
+ cur_pos1 += d_off;
+
+ edge->pos = cur_pos1 - cur_len / 2;
+ edge2->pos = edge->pos + cur_len;
+ }
+ else
+ edge->pos = FT_PIX_ROUND( edge->opos );
+
+ AF_LOG(( "ANCHOR: edge %d (opos=%.2f) and %d (opos=%.2f) "
+ "snapped to (%.2f) (%.2f)\n",
+ edge-edges, edge->opos / 64.0,
+ edge2-edges, edge2->opos / 64.0,
+ edge->pos / 64.0, edge2->pos / 64.0 ));
+ anchor = edge;
+
+ edge->flags |= AF_EDGE_DONE;
+
+ af_latin_align_linked_edge( hints, dim, edge, edge2 );
+ }
+ else
+ {
+ FT_Pos org_pos, org_len, org_center, cur_len;
+ FT_Pos cur_pos1, cur_pos2, delta1, delta2;
+
+
+ org_pos = anchor->pos + ( edge->opos - anchor->opos );
+ org_len = edge2->opos - edge->opos;
+ org_center = org_pos + ( org_len >> 1 );
+
+ cur_len = af_latin_compute_stem_width(
+ hints, dim, org_len,
+ (AF_Edge_Flags)edge->flags,
+ (AF_Edge_Flags)edge2->flags );
+
+ if ( edge2->flags & AF_EDGE_DONE )
+ edge->pos = edge2->pos - cur_len;
+
+ else if ( cur_len < 96 )
+ {
+ FT_Pos u_off, d_off;
+
+
+ cur_pos1 = FT_PIX_ROUND( org_center );
+
+ if (cur_len <= 64 )
+ u_off = d_off = 32;
+ else
+ {
+ u_off = 38;
+ d_off = 26;
+ }
+
+ delta1 = org_center - ( cur_pos1 - u_off );
+ if ( delta1 < 0 )
+ delta1 = -delta1;
+
+ delta2 = org_center - ( cur_pos1 + d_off );
+ if ( delta2 < 0 )
+ delta2 = -delta2;
+
+ if ( delta1 < delta2 )
+ cur_pos1 -= u_off;
+ else
+ cur_pos1 += d_off;
+
+ edge->pos = cur_pos1 - cur_len / 2;
+ edge2->pos = cur_pos1 + cur_len / 2;
+
+ AF_LOG(( "STEM: %d (opos=%.2f) to %d (opos=%.2f) "
+ "snapped to (%.2f) and (%.2f)\n",
+ edge-edges, edge->opos / 64.0,
+ edge2-edges, edge2->opos / 64.0,
+ edge->pos / 64.0, edge2->pos / 64.0 ));
+ }
+ else
+ {
+ org_pos = anchor->pos + ( edge->opos - anchor->opos );
+ org_len = edge2->opos - edge->opos;
+ org_center = org_pos + ( org_len >> 1 );
+
+ cur_len = af_latin_compute_stem_width(
+ hints, dim, org_len,
+ (AF_Edge_Flags)edge->flags,
+ (AF_Edge_Flags)edge2->flags );
+
+ cur_pos1 = FT_PIX_ROUND( org_pos );
+ delta1 = cur_pos1 + ( cur_len >> 1 ) - org_center;
+ if ( delta1 < 0 )
+ delta1 = -delta1;
+
+ cur_pos2 = FT_PIX_ROUND( org_pos + org_len ) - cur_len;
+ delta2 = cur_pos2 + ( cur_len >> 1 ) - org_center;
+ if ( delta2 < 0 )
+ delta2 = -delta2;
+
+ edge->pos = ( delta1 < delta2 ) ? cur_pos1 : cur_pos2;
+ edge2->pos = edge->pos + cur_len;
+
+ AF_LOG(( "STEM: %d (opos=%.2f) to %d (opos=%.2f) "
+ "snapped to (%.2f) and (%.2f)\n",
+ edge-edges, edge->opos / 64.0,
+ edge2-edges, edge2->opos / 64.0,
+ edge->pos / 64.0, edge2->pos / 64.0 ));
+ }
+
+ edge->flags |= AF_EDGE_DONE;
+ edge2->flags |= AF_EDGE_DONE;
+
+ if ( edge > edges && edge->pos < edge[-1].pos )
+ {
+ AF_LOG(( "BOUND: %d (pos=%.2f) to (%.2f)\n",
+ edge-edges, edge->pos / 64.0, edge[-1].pos / 64.0 ));
+ edge->pos = edge[-1].pos;
+ }
+ }
+ }
+
+ /* make sure that lowercase m's maintain their symmetry */
+
+ /* In general, lowercase m's have six vertical edges if they are sans */
+ /* serif, or twelve if they are with serifs. This implementation is */
+ /* based on that assumption, and seems to work very well with most */
+ /* faces. However, if for a certain face this assumption is not */
+ /* true, the m is just rendered like before. In addition, any stem */
+ /* correction will only be applied to symmetrical glyphs (even if the */
+ /* glyph is not an m), so the potential for unwanted distortion is */
+ /* relatively low. */
+
+ /* We don't handle horizontal edges since we can't easily assure that */
+ /* the third (lowest) stem aligns with the base line; it might end up */
+ /* one pixel higher or lower. */
+
+ n_edges = edge_limit - edges;
+ if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) )
+ {
+ AF_Edge edge1, edge2, edge3;
+ FT_Pos dist1, dist2, span, delta;
+
+
+ if ( n_edges == 6 )
+ {
+ edge1 = edges;
+ edge2 = edges + 2;
+ edge3 = edges + 4;
+ }
+ else
+ {
+ edge1 = edges + 1;
+ edge2 = edges + 5;
+ edge3 = edges + 9;
+ }
+
+ dist1 = edge2->opos - edge1->opos;
+ dist2 = edge3->opos - edge2->opos;
+
+ span = dist1 - dist2;
+ if ( span < 0 )
+ span = -span;
+
+ if ( span < 8 )
+ {
+ delta = edge3->pos - ( 2 * edge2->pos - edge1->pos );
+ edge3->pos -= delta;
+ if ( edge3->link )
+ edge3->link->pos -= delta;
+
+ /* move the serifs along with the stem */
+ if ( n_edges == 12 )
+ {
+ ( edges + 8 )->pos -= delta;
+ ( edges + 11 )->pos -= delta;
+ }
+
+ edge3->flags |= AF_EDGE_DONE;
+ if ( edge3->link )
+ edge3->link->flags |= AF_EDGE_DONE;
+ }
+ }
+
+ if ( has_serifs || !anchor )
+ {
+ /*
+ * now hint the remaining edges (serifs and single) in order
+ * to complete our processing
+ */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ FT_Pos delta;
+
+
+ if ( edge->flags & AF_EDGE_DONE )
+ continue;
+
+ delta = 1000;
+
+ if ( edge->serif )
+ {
+ delta = edge->serif->opos - edge->opos;
+ if ( delta < 0 )
+ delta = -delta;
+ }
+
+ if ( delta < 64 + 16 )
+ {
+ af_latin_align_serif_edge( hints, edge->serif, edge );
+ AF_LOG(( "SERIF: edge %d (opos=%.2f) serif to %d (opos=%.2f) "
+ "aligned to (%.2f)\n",
+ edge-edges, edge->opos / 64.0,
+ edge->serif - edges, edge->serif->opos / 64.0,
+ edge->pos / 64.0 ));
+ }
+ else if ( !anchor )
+ {
+ AF_LOG(( "SERIF_ANCHOR: edge %d (opos=%.2f) snapped to (%.2f)\n",
+ edge-edges, edge->opos / 64.0, edge->pos / 64.0 ));
+ edge->pos = FT_PIX_ROUND( edge->opos );
+ anchor = edge;
+ }
+ else
+ {
+ AF_Edge before, after;
+
+
+ for ( before = edge - 1; before >= edges; before-- )
+ if ( before->flags & AF_EDGE_DONE )
+ break;
+
+ for ( after = edge + 1; after < edge_limit; after++ )
+ if ( after->flags & AF_EDGE_DONE )
+ break;
+
+ if ( before >= edges && before < edge &&
+ after < edge_limit && after > edge )
+ {
+ if ( after->opos == before->opos )
+ edge->pos = before->pos;
+ else
+ edge->pos = before->pos +
+ FT_MulDiv( edge->opos - before->opos,
+ after->pos - before->pos,
+ after->opos - before->opos );
+ AF_LOG(( "SERIF_LINK1: edge %d (opos=%.2f) snapped to (%.2f) "
+ "from %d (opos=%.2f)\n",
+ edge-edges, edge->opos / 64.0,
+ edge->pos / 64.0, before - edges,
+ before->opos / 64.0 ));
+ }
+ else
+ {
+ edge->pos = anchor->pos +
+ ( ( edge->opos - anchor->opos + 16 ) & ~31 );
+ AF_LOG(( "SERIF_LINK2: edge %d (opos=%.2f) snapped to (%.2f)\n",
+ edge-edges, edge->opos / 64.0, edge->pos / 64.0 ));
+ }
+ }
+
+ edge->flags |= AF_EDGE_DONE;
+
+ if ( edge > edges && edge->pos < edge[-1].pos )
+ edge->pos = edge[-1].pos;
+
+ if ( edge + 1 < edge_limit &&
+ edge[1].flags & AF_EDGE_DONE &&
+ edge->pos > edge[1].pos )
+ edge->pos = edge[1].pos;
+ }
+ }
+ }
+
+
+ static FT_Error
+ af_latin_hints_apply( AF_GlyphHints hints,
+ FT_Outline* outline,
+ AF_LatinMetrics metrics )
+ {
+ FT_Error error;
+ int dim;
+
+
+ error = af_glyph_hints_reload( hints, outline, 1 );
+ if ( error )
+ goto Exit;
+
+ /* analyze glyph outline */
+#ifdef AF_USE_WARPER
+ if ( metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT ||
+ AF_HINTS_DO_HORIZONTAL( hints ) )
+#else
+ if ( AF_HINTS_DO_HORIZONTAL( hints ) )
+#endif
+ {
+ error = af_latin_hints_detect_features( hints, AF_DIMENSION_HORZ );
+ if ( error )
+ goto Exit;
+ }
+
+ if ( AF_HINTS_DO_VERTICAL( hints ) )
+ {
+ error = af_latin_hints_detect_features( hints, AF_DIMENSION_VERT );
+ if ( error )
+ goto Exit;
+
+ af_latin_hints_compute_blue_edges( hints, metrics );
+ }
+
+ /* grid-fit the outline */
+ for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
+ {
+#ifdef AF_USE_WARPER
+ if ( ( dim == AF_DIMENSION_HORZ &&
+ metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT ) )
+ {
+ AF_WarperRec warper;
+ FT_Fixed scale;
+ FT_Pos delta;
+
+
+ af_warper_compute( &warper, hints, dim, &scale, &delta );
+ af_glyph_hints_scale_dim( hints, dim, scale, delta );
+ continue;
+ }
+#endif
+
+ if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) ||
+ ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) )
+ {
+ af_latin_hint_edges( hints, (AF_Dimension)dim );
+ af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim );
+ af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim );
+ af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim );
+ }
+ }
+ af_glyph_hints_save( hints, outline );
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** L A T I N S C R I P T C L A S S *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /* XXX: this should probably fine tuned to differentiate better between */
+ /* scripts... */
+
+ static const AF_Script_UniRangeRec af_latin_uniranges[] =
+ {
+ { 0x0020 , 0x007F }, /* Basic Latin (no control chars) */
+ { 0x00A0 , 0x00FF }, /* Latin-1 Supplement (no control chars) */
+ { 0x0100 , 0x017F }, /* Latin Extended-A */
+ { 0x0180 , 0x024F }, /* Latin Extended-B */
+ { 0x0250 , 0x02AF }, /* IPA Extensions */
+ { 0x02B0 , 0x02FF }, /* Spacing Modifier Letters */
+ { 0x0300 , 0x036F }, /* Combining Diacritical Marks */
+ { 0x0370 , 0x03FF }, /* Greek and Coptic */
+ { 0x0400 , 0x04FF }, /* Cyrillic */
+ { 0x0500 , 0x052F }, /* Cyrillic Supplement */
+ { 0x1D00 , 0x1D7F }, /* Phonetic Extensions */
+ { 0x1D80 , 0x1DBF }, /* Phonetic Extensions Supplement */
+ { 0x1DC0 , 0x1DFF }, /* Combining Diacritical Marks Supplement */
+ { 0x1E00 , 0x1EFF }, /* Latin Extended Additional */
+ { 0x1F00 , 0x1FFF }, /* Greek Extended */
+ { 0x2000 , 0x206F }, /* General Punctuation */
+ { 0x2070 , 0x209F }, /* Superscripts and Subscripts */
+ { 0x20A0 , 0x20CF }, /* Currency Symbols */
+ { 0x2150 , 0x218F }, /* Number Forms */
+ { 0x2460 , 0x24FF }, /* Enclosed Alphanumerics */
+ { 0x2C60 , 0x2C7F }, /* Latin Extended-C */
+ { 0x2DE0 , 0x2DFF }, /* Cyrillic Extended-A */
+ { 0xA640U , 0xA69FU }, /* Cyrillic Extended-B */
+ { 0xA720U , 0xA7FFU }, /* Latin Extended-D */
+ { 0xFB00U , 0xFB06U }, /* Alphab. Present. Forms (Latin Ligs) */
+ { 0x1D400UL, 0x1D7FFUL }, /* Mathematical Alphanumeric Symbols */
+ { 0 , 0 }
+ };
+
+
+ FT_CALLBACK_TABLE_DEF const AF_ScriptClassRec
+ af_latin_script_class =
+ {
+ AF_SCRIPT_LATIN,
+ af_latin_uniranges,
+
+ sizeof( AF_LatinMetricsRec ),
+
+ (AF_Script_InitMetricsFunc) af_latin_metrics_init,
+ (AF_Script_ScaleMetricsFunc)af_latin_metrics_scale,
+ (AF_Script_DoneMetricsFunc) NULL,
+
+ (AF_Script_InitHintsFunc) af_latin_hints_init,
+ (AF_Script_ApplyHintsFunc) af_latin_hints_apply
+ };
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/aflatin.h b/src/3rdparty/freetype/src/autofit/aflatin.h
new file mode 100644
index 0000000000..3251d3783f
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/aflatin.h
@@ -0,0 +1,209 @@
+/***************************************************************************/
+/* */
+/* aflatin.h */
+/* */
+/* Auto-fitter hinting routines for latin script (specification). */
+/* */
+/* Copyright 2003, 2004, 2005, 2006, 2007 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AFLATIN_H__
+#define __AFLATIN_H__
+
+#include "afhints.h"
+
+
+FT_BEGIN_HEADER
+
+
+ /* the latin-specific script class */
+
+ FT_CALLBACK_TABLE const AF_ScriptClassRec
+ af_latin_script_class;
+
+
+/* constants are given with units_per_em == 2048 in mind */
+#define AF_LATIN_CONSTANT( metrics, c ) \
+ ( ( (c) * (FT_Long)( (AF_LatinMetrics)(metrics) )->units_per_em ) / 2048 )
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** L A T I N G L O B A L M E T R I C S *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ /*
+ * The following declarations could be embedded in the file `aflatin.c';
+ * they have been made semi-public to allow alternate script hinters to
+ * re-use some of them.
+ */
+
+
+ /* Latin (global) metrics management */
+
+ enum
+ {
+ AF_LATIN_BLUE_CAPITAL_TOP,
+ AF_LATIN_BLUE_CAPITAL_BOTTOM,
+ AF_LATIN_BLUE_SMALL_F_TOP,
+ AF_LATIN_BLUE_SMALL_TOP,
+ AF_LATIN_BLUE_SMALL_BOTTOM,
+ AF_LATIN_BLUE_SMALL_MINOR,
+
+ AF_LATIN_BLUE_MAX
+ };
+
+
+#define AF_LATIN_IS_TOP_BLUE( b ) ( (b) == AF_LATIN_BLUE_CAPITAL_TOP || \
+ (b) == AF_LATIN_BLUE_SMALL_F_TOP || \
+ (b) == AF_LATIN_BLUE_SMALL_TOP )
+
+#define AF_LATIN_MAX_WIDTHS 16
+#define AF_LATIN_MAX_BLUES AF_LATIN_BLUE_MAX
+
+
+ enum
+ {
+ AF_LATIN_BLUE_ACTIVE = 1 << 0,
+ AF_LATIN_BLUE_TOP = 1 << 1,
+ AF_LATIN_BLUE_ADJUSTMENT = 1 << 2, /* used for scale adjustment */
+ /* optimization */
+ AF_LATIN_BLUE_FLAG_MAX
+ };
+
+
+ typedef struct AF_LatinBlueRec_
+ {
+ AF_WidthRec ref;
+ AF_WidthRec shoot;
+ FT_UInt flags;
+
+ } AF_LatinBlueRec, *AF_LatinBlue;
+
+
+ typedef struct AF_LatinAxisRec_
+ {
+ FT_Fixed scale;
+ FT_Pos delta;
+
+ FT_UInt width_count;
+ AF_WidthRec widths[AF_LATIN_MAX_WIDTHS];
+ FT_Pos edge_distance_threshold;
+ FT_Pos standard_width;
+ FT_Bool extra_light;
+
+ /* ignored for horizontal metrics */
+ FT_Bool control_overshoot;
+ FT_UInt blue_count;
+ AF_LatinBlueRec blues[AF_LATIN_BLUE_MAX];
+
+ FT_Fixed org_scale;
+ FT_Pos org_delta;
+
+ } AF_LatinAxisRec, *AF_LatinAxis;
+
+
+ typedef struct AF_LatinMetricsRec_
+ {
+ AF_ScriptMetricsRec root;
+ FT_UInt units_per_em;
+ AF_LatinAxisRec axis[AF_DIMENSION_MAX];
+
+ } AF_LatinMetricsRec, *AF_LatinMetrics;
+
+
+ FT_LOCAL( FT_Error )
+ af_latin_metrics_init( AF_LatinMetrics metrics,
+ FT_Face face );
+
+ FT_LOCAL( void )
+ af_latin_metrics_scale( AF_LatinMetrics metrics,
+ AF_Scaler scaler );
+
+ FT_LOCAL( void )
+ af_latin_metrics_init_widths( AF_LatinMetrics metrics,
+ FT_Face face,
+ FT_ULong charcode );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** L A T I N G L Y P H A N A L Y S I S *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ enum
+ {
+ AF_LATIN_HINTS_HORZ_SNAP = 1 << 0, /* enable stem width snapping */
+ AF_LATIN_HINTS_VERT_SNAP = 1 << 1, /* enable stem height snapping */
+ AF_LATIN_HINTS_STEM_ADJUST = 1 << 2, /* enable stem width/height */
+ /* adjustment */
+ AF_LATIN_HINTS_MONO = 1 << 3 /* indicate monochrome */
+ /* rendering */
+ };
+
+
+#define AF_LATIN_HINTS_DO_HORZ_SNAP( h ) \
+ AF_HINTS_TEST_OTHER( h, AF_LATIN_HINTS_HORZ_SNAP )
+
+#define AF_LATIN_HINTS_DO_VERT_SNAP( h ) \
+ AF_HINTS_TEST_OTHER( h, AF_LATIN_HINTS_VERT_SNAP )
+
+#define AF_LATIN_HINTS_DO_STEM_ADJUST( h ) \
+ AF_HINTS_TEST_OTHER( h, AF_LATIN_HINTS_STEM_ADJUST )
+
+#define AF_LATIN_HINTS_DO_MONO( h ) \
+ AF_HINTS_TEST_OTHER( h, AF_LATIN_HINTS_MONO )
+
+
+ /*
+ * This shouldn't normally be exported. However, other scripts might
+ * like to use this function as-is.
+ */
+ FT_LOCAL( FT_Error )
+ af_latin_hints_compute_segments( AF_GlyphHints hints,
+ AF_Dimension dim );
+
+ /*
+ * This shouldn't normally be exported. However, other scripts might
+ * want to use this function as-is.
+ */
+ FT_LOCAL( void )
+ af_latin_hints_link_segments( AF_GlyphHints hints,
+ AF_Dimension dim );
+
+ /*
+ * This shouldn't normally be exported. However, other scripts might
+ * want to use this function as-is.
+ */
+ FT_LOCAL( FT_Error )
+ af_latin_hints_compute_edges( AF_GlyphHints hints,
+ AF_Dimension dim );
+
+ FT_LOCAL( FT_Error )
+ af_latin_hints_detect_features( AF_GlyphHints hints,
+ AF_Dimension dim );
+
+/* */
+
+FT_END_HEADER
+
+#endif /* __AFLATIN_H__ */
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/aflatin2.c b/src/3rdparty/freetype/src/autofit/aflatin2.c
new file mode 100644
index 0000000000..14327b172b
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/aflatin2.c
@@ -0,0 +1,2292 @@
+/***************************************************************************/
+/* */
+/* aflatin.c */
+/* */
+/* Auto-fitter hinting routines for latin script (body). */
+/* */
+/* Copyright 2003, 2004, 2005, 2006, 2007, 2008 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "aflatin.h"
+#include "aflatin2.h"
+#include "aferrors.h"
+
+
+#ifdef AF_USE_WARPER
+#include "afwarp.h"
+#endif
+
+ FT_LOCAL_DEF( FT_Error )
+ af_latin2_hints_compute_segments( AF_GlyphHints hints,
+ AF_Dimension dim );
+
+ FT_LOCAL_DEF( void )
+ af_latin2_hints_link_segments( AF_GlyphHints hints,
+ AF_Dimension dim );
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** L A T I N G L O B A L M E T R I C S *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_LOCAL_DEF( void )
+ af_latin2_metrics_init_widths( AF_LatinMetrics metrics,
+ FT_Face face,
+ FT_ULong charcode )
+ {
+ /* scan the array of segments in each direction */
+ AF_GlyphHintsRec hints[1];
+
+
+ af_glyph_hints_init( hints, face->memory );
+
+ metrics->axis[AF_DIMENSION_HORZ].width_count = 0;
+ metrics->axis[AF_DIMENSION_VERT].width_count = 0;
+
+ {
+ FT_Error error;
+ FT_UInt glyph_index;
+ int dim;
+ AF_LatinMetricsRec dummy[1];
+ AF_Scaler scaler = &dummy->root.scaler;
+
+
+ glyph_index = FT_Get_Char_Index( face, charcode );
+ if ( glyph_index == 0 )
+ goto Exit;
+
+ error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
+ if ( error || face->glyph->outline.n_points <= 0 )
+ goto Exit;
+
+ FT_ZERO( dummy );
+
+ dummy->units_per_em = metrics->units_per_em;
+ scaler->x_scale = scaler->y_scale = 0x10000L;
+ scaler->x_delta = scaler->y_delta = 0;
+ scaler->face = face;
+ scaler->render_mode = FT_RENDER_MODE_NORMAL;
+ scaler->flags = 0;
+
+ af_glyph_hints_rescale( hints, (AF_ScriptMetrics)dummy );
+
+ error = af_glyph_hints_reload( hints, &face->glyph->outline, 0 );
+ if ( error )
+ goto Exit;
+
+ for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
+ {
+ AF_LatinAxis axis = &metrics->axis[dim];
+ AF_AxisHints axhints = &hints->axis[dim];
+ AF_Segment seg, limit, link;
+ FT_UInt num_widths = 0;
+
+
+ error = af_latin2_hints_compute_segments( hints,
+ (AF_Dimension)dim );
+ if ( error )
+ goto Exit;
+
+ af_latin2_hints_link_segments( hints,
+ (AF_Dimension)dim );
+
+ seg = axhints->segments;
+ limit = seg + axhints->num_segments;
+
+ for ( ; seg < limit; seg++ )
+ {
+ link = seg->link;
+
+ /* we only consider stem segments there! */
+ if ( link && link->link == seg && link > seg )
+ {
+ FT_Pos dist;
+
+
+ dist = seg->pos - link->pos;
+ if ( dist < 0 )
+ dist = -dist;
+
+ if ( num_widths < AF_LATIN_MAX_WIDTHS )
+ axis->widths[ num_widths++ ].org = dist;
+ }
+ }
+
+ af_sort_widths( num_widths, axis->widths );
+ axis->width_count = num_widths;
+ }
+
+ Exit:
+ for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
+ {
+ AF_LatinAxis axis = &metrics->axis[dim];
+ FT_Pos stdw;
+
+
+ stdw = ( axis->width_count > 0 )
+ ? axis->widths[0].org
+ : AF_LATIN_CONSTANT( metrics, 50 );
+
+ /* let's try 20% of the smallest width */
+ axis->edge_distance_threshold = stdw / 5;
+ axis->standard_width = stdw;
+ axis->extra_light = 0;
+ }
+ }
+
+ af_glyph_hints_done( hints );
+ }
+
+
+
+#define AF_LATIN_MAX_TEST_CHARACTERS 12
+
+
+ static const char* const af_latin2_blue_chars[AF_LATIN_MAX_BLUES] =
+ {
+ "THEZOCQS",
+ "HEZLOCUS",
+ "fijkdbh",
+ "xzroesc",
+ "xzroesc",
+ "pqgjy"
+ };
+
+
+ static void
+ af_latin2_metrics_init_blues( AF_LatinMetrics metrics,
+ FT_Face face )
+ {
+ FT_Pos flats [AF_LATIN_MAX_TEST_CHARACTERS];
+ FT_Pos rounds[AF_LATIN_MAX_TEST_CHARACTERS];
+ FT_Int num_flats;
+ FT_Int num_rounds;
+ FT_Int bb;
+ AF_LatinBlue blue;
+ FT_Error error;
+ AF_LatinAxis axis = &metrics->axis[AF_DIMENSION_VERT];
+ FT_GlyphSlot glyph = face->glyph;
+
+
+ /* we compute the blues simply by loading each character from the */
+ /* 'af_latin2_blue_chars[blues]' string, then compute its top-most or */
+ /* bottom-most points (depending on `AF_IS_TOP_BLUE') */
+
+ AF_LOG(( "blue zones computation\n" ));
+ AF_LOG(( "------------------------------------------------\n" ));
+
+ for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ )
+ {
+ const char* p = af_latin2_blue_chars[bb];
+ const char* limit = p + AF_LATIN_MAX_TEST_CHARACTERS;
+ FT_Pos* blue_ref;
+ FT_Pos* blue_shoot;
+
+
+ AF_LOG(( "blue %3d: ", bb ));
+
+ num_flats = 0;
+ num_rounds = 0;
+
+ for ( ; p < limit && *p; p++ )
+ {
+ FT_UInt glyph_index;
+ FT_Int best_point, best_y, best_first, best_last;
+ FT_Vector* points;
+ FT_Bool round;
+
+
+ AF_LOG(( "'%c'", *p ));
+
+ /* load the character in the face -- skip unknown or empty ones */
+ glyph_index = FT_Get_Char_Index( face, (FT_UInt)*p );
+ if ( glyph_index == 0 )
+ continue;
+
+ error = FT_Load_Glyph( face, glyph_index, FT_LOAD_NO_SCALE );
+ if ( error || glyph->outline.n_points <= 0 )
+ continue;
+
+ /* now compute min or max point indices and coordinates */
+ points = glyph->outline.points;
+ best_point = -1;
+ best_y = 0; /* make compiler happy */
+ best_first = 0; /* ditto */
+ best_last = 0; /* ditto */
+
+ {
+ FT_Int nn;
+ FT_Int first = 0;
+ FT_Int last = -1;
+
+
+ for ( nn = 0; nn < glyph->outline.n_contours; first = last+1, nn++ )
+ {
+ FT_Int old_best_point = best_point;
+ FT_Int pp;
+
+
+ last = glyph->outline.contours[nn];
+
+ /* Avoid single-point contours since they are never rasterized. */
+ /* In some fonts, they correspond to mark attachment points */
+ /* which are way outside of the glyph's real outline. */
+ if ( last == first )
+ continue;
+
+ if ( AF_LATIN_IS_TOP_BLUE( bb ) )
+ {
+ for ( pp = first; pp <= last; pp++ )
+ if ( best_point < 0 || points[pp].y > best_y )
+ {
+ best_point = pp;
+ best_y = points[pp].y;
+ }
+ }
+ else
+ {
+ for ( pp = first; pp <= last; pp++ )
+ if ( best_point < 0 || points[pp].y < best_y )
+ {
+ best_point = pp;
+ best_y = points[pp].y;
+ }
+ }
+
+ if ( best_point != old_best_point )
+ {
+ best_first = first;
+ best_last = last;
+ }
+ }
+ AF_LOG(( "%5d", best_y ));
+ }
+
+ /* now check whether the point belongs to a straight or round */
+ /* segment; we first need to find in which contour the extremum */
+ /* lies, then inspect its previous and next points */
+ {
+ FT_Int start, end, prev, next;
+ FT_Pos dist;
+
+
+ /* now look for the previous and next points that are not on the */
+ /* same Y coordinate. Threshold the `closeness'... */
+ start = end = best_point;
+
+ do
+ {
+ prev = start-1;
+ if ( prev < best_first )
+ prev = best_last;
+
+ dist = points[prev].y - best_y;
+ if ( dist < -5 || dist > 5 )
+ break;
+
+ start = prev;
+
+ } while ( start != best_point );
+
+ do
+ {
+ next = end+1;
+ if ( next > best_last )
+ next = best_first;
+
+ dist = points[next].y - best_y;
+ if ( dist < -5 || dist > 5 )
+ break;
+
+ end = next;
+
+ } while ( end != best_point );
+
+ /* now, set the `round' flag depending on the segment's kind */
+ round = FT_BOOL(
+ FT_CURVE_TAG( glyph->outline.tags[start] ) != FT_CURVE_TAG_ON ||
+ FT_CURVE_TAG( glyph->outline.tags[ end ] ) != FT_CURVE_TAG_ON );
+
+ AF_LOG(( "%c ", round ? 'r' : 'f' ));
+ }
+
+ if ( round )
+ rounds[num_rounds++] = best_y;
+ else
+ flats[num_flats++] = best_y;
+ }
+
+ AF_LOG(( "\n" ));
+
+ if ( num_flats == 0 && num_rounds == 0 )
+ {
+ /*
+ * we couldn't find a single glyph to compute this blue zone,
+ * we will simply ignore it then
+ */
+ AF_LOG(( "empty!\n" ));
+ continue;
+ }
+
+ /* we have computed the contents of the `rounds' and `flats' tables, */
+ /* now determine the reference and overshoot position of the blue -- */
+ /* we simply take the median value after a simple sort */
+ af_sort_pos( num_rounds, rounds );
+ af_sort_pos( num_flats, flats );
+
+ blue = & axis->blues[axis->blue_count];
+ blue_ref = & blue->ref.org;
+ blue_shoot = & blue->shoot.org;
+
+ axis->blue_count++;
+
+ if ( num_flats == 0 )
+ {
+ *blue_ref =
+ *blue_shoot = rounds[num_rounds / 2];
+ }
+ else if ( num_rounds == 0 )
+ {
+ *blue_ref =
+ *blue_shoot = flats[num_flats / 2];
+ }
+ else
+ {
+ *blue_ref = flats[num_flats / 2];
+ *blue_shoot = rounds[num_rounds / 2];
+ }
+
+ /* there are sometimes problems: if the overshoot position of top */
+ /* zones is under its reference position, or the opposite for bottom */
+ /* zones. We must thus check everything there and correct the errors */
+ if ( *blue_shoot != *blue_ref )
+ {
+ FT_Pos ref = *blue_ref;
+ FT_Pos shoot = *blue_shoot;
+ FT_Bool over_ref = FT_BOOL( shoot > ref );
+
+
+ if ( AF_LATIN_IS_TOP_BLUE( bb ) ^ over_ref )
+ *blue_shoot = *blue_ref = ( shoot + ref ) / 2;
+ }
+
+ blue->flags = 0;
+ if ( AF_LATIN_IS_TOP_BLUE( bb ) )
+ blue->flags |= AF_LATIN_BLUE_TOP;
+
+ /*
+ * The following flags is used later to adjust the y and x scales
+ * in order to optimize the pixel grid alignment of the top of small
+ * letters.
+ */
+ if ( bb == AF_LATIN_BLUE_SMALL_TOP )
+ blue->flags |= AF_LATIN_BLUE_ADJUSTMENT;
+
+ AF_LOG(( "-- ref = %ld, shoot = %ld\n", *blue_ref, *blue_shoot ));
+ }
+
+ return;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ af_latin2_metrics_init( AF_LatinMetrics metrics,
+ FT_Face face )
+ {
+ FT_Error error = AF_Err_Ok;
+ FT_CharMap oldmap = face->charmap;
+ FT_UInt ee;
+
+ static const FT_Encoding latin_encodings[] =
+ {
+ FT_ENCODING_UNICODE,
+ FT_ENCODING_APPLE_ROMAN,
+ FT_ENCODING_ADOBE_STANDARD,
+ FT_ENCODING_ADOBE_LATIN_1,
+ FT_ENCODING_NONE /* end of list */
+ };
+
+
+ metrics->units_per_em = face->units_per_EM;
+
+ /* do we have a latin charmap in there? */
+ for ( ee = 0; latin_encodings[ee] != FT_ENCODING_NONE; ee++ )
+ {
+ error = FT_Select_Charmap( face, latin_encodings[ee] );
+ if ( !error )
+ break;
+ }
+
+ if ( !error )
+ {
+ /* For now, compute the standard width and height from the `o'. */
+ af_latin2_metrics_init_widths( metrics, face, 'o' );
+ af_latin2_metrics_init_blues( metrics, face );
+ }
+
+ FT_Set_Charmap( face, oldmap );
+ return AF_Err_Ok;
+ }
+
+
+ static void
+ af_latin2_metrics_scale_dim( AF_LatinMetrics metrics,
+ AF_Scaler scaler,
+ AF_Dimension dim )
+ {
+ FT_Fixed scale;
+ FT_Pos delta;
+ AF_LatinAxis axis;
+ FT_UInt nn;
+
+
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ scale = scaler->x_scale;
+ delta = scaler->x_delta;
+ }
+ else
+ {
+ scale = scaler->y_scale;
+ delta = scaler->y_delta;
+ }
+
+ axis = &metrics->axis[dim];
+
+ if ( axis->org_scale == scale && axis->org_delta == delta )
+ return;
+
+ axis->org_scale = scale;
+ axis->org_delta = delta;
+
+ /*
+ * correct Y scale to optimize the alignment of the top of small
+ * letters to the pixel grid
+ */
+ if ( dim == AF_DIMENSION_VERT )
+ {
+ AF_LatinAxis vaxis = &metrics->axis[AF_DIMENSION_VERT];
+ AF_LatinBlue blue = NULL;
+
+
+ for ( nn = 0; nn < vaxis->blue_count; nn++ )
+ {
+ if ( vaxis->blues[nn].flags & AF_LATIN_BLUE_ADJUSTMENT )
+ {
+ blue = &vaxis->blues[nn];
+ break;
+ }
+ }
+
+ if ( blue )
+ {
+ FT_Pos scaled = FT_MulFix( blue->shoot.org, scaler->y_scale );
+ FT_Pos fitted = ( scaled + 40 ) & ~63;
+
+#if 1
+ if ( scaled != fitted ) {
+ scale = FT_MulDiv( scale, fitted, scaled );
+ AF_LOG(( "== scaled x-top = %.2g fitted = %.2g, scaling = %.4g\n", scaled/64.0, fitted/64.0, (fitted*1.0)/scaled ));
+ }
+#endif
+ }
+ }
+
+ axis->scale = scale;
+ axis->delta = delta;
+
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ metrics->root.scaler.x_scale = scale;
+ metrics->root.scaler.x_delta = delta;
+ }
+ else
+ {
+ metrics->root.scaler.y_scale = scale;
+ metrics->root.scaler.y_delta = delta;
+ }
+
+ /* scale the standard widths */
+ for ( nn = 0; nn < axis->width_count; nn++ )
+ {
+ AF_Width width = axis->widths + nn;
+
+
+ width->cur = FT_MulFix( width->org, scale );
+ width->fit = width->cur;
+ }
+
+ /* an extra-light axis corresponds to a standard width that is */
+ /* smaller than 0.75 pixels */
+ axis->extra_light =
+ (FT_Bool)( FT_MulFix( axis->standard_width, scale ) < 32 + 8 );
+
+ if ( dim == AF_DIMENSION_VERT )
+ {
+ /* scale the blue zones */
+ for ( nn = 0; nn < axis->blue_count; nn++ )
+ {
+ AF_LatinBlue blue = &axis->blues[nn];
+ FT_Pos dist;
+
+
+ blue->ref.cur = FT_MulFix( blue->ref.org, scale ) + delta;
+ blue->ref.fit = blue->ref.cur;
+ blue->shoot.cur = FT_MulFix( blue->shoot.org, scale ) + delta;
+ blue->shoot.fit = blue->shoot.cur;
+ blue->flags &= ~AF_LATIN_BLUE_ACTIVE;
+
+ /* a blue zone is only active if it is less than 3/4 pixels tall */
+ dist = FT_MulFix( blue->ref.org - blue->shoot.org, scale );
+ if ( dist <= 48 && dist >= -48 )
+ {
+ FT_Pos delta1, delta2;
+
+ delta1 = blue->shoot.org - blue->ref.org;
+ delta2 = delta1;
+ if ( delta1 < 0 )
+ delta2 = -delta2;
+
+ delta2 = FT_MulFix( delta2, scale );
+
+ if ( delta2 < 32 )
+ delta2 = 0;
+ else if ( delta2 < 64 )
+ delta2 = 32 + ( ( ( delta2 - 32 ) + 16 ) & ~31 );
+ else
+ delta2 = FT_PIX_ROUND( delta2 );
+
+ if ( delta1 < 0 )
+ delta2 = -delta2;
+
+ blue->ref.fit = FT_PIX_ROUND( blue->ref.cur );
+ blue->shoot.fit = blue->ref.fit + delta2;
+
+ AF_LOG(( ">> activating blue zone %d: ref.cur=%.2g ref.fit=%.2g shoot.cur=%.2g shoot.fit=%.2g\n",
+ nn, blue->ref.cur/64.0, blue->ref.fit/64.0,
+ blue->shoot.cur/64.0, blue->shoot.fit/64.0 ));
+
+ blue->flags |= AF_LATIN_BLUE_ACTIVE;
+ }
+ }
+ }
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_latin2_metrics_scale( AF_LatinMetrics metrics,
+ AF_Scaler scaler )
+ {
+ metrics->root.scaler.render_mode = scaler->render_mode;
+ metrics->root.scaler.face = scaler->face;
+
+ af_latin2_metrics_scale_dim( metrics, scaler, AF_DIMENSION_HORZ );
+ af_latin2_metrics_scale_dim( metrics, scaler, AF_DIMENSION_VERT );
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** L A T I N G L Y P H A N A L Y S I S *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+#define SORT_SEGMENTS
+
+ FT_LOCAL_DEF( FT_Error )
+ af_latin2_hints_compute_segments( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_AxisHints axis = &hints->axis[dim];
+ FT_Memory memory = hints->memory;
+ FT_Error error = AF_Err_Ok;
+ AF_Segment segment = NULL;
+ AF_SegmentRec seg0;
+ AF_Point* contour = hints->contours;
+ AF_Point* contour_limit = contour + hints->num_contours;
+ AF_Direction major_dir, segment_dir;
+
+
+ FT_ZERO( &seg0 );
+ seg0.score = 32000;
+ seg0.flags = AF_EDGE_NORMAL;
+
+ major_dir = (AF_Direction)FT_ABS( axis->major_dir );
+ segment_dir = major_dir;
+
+ axis->num_segments = 0;
+
+ /* set up (u,v) in each point */
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ AF_Point point = hints->points;
+ AF_Point limit = point + hints->num_points;
+
+
+ for ( ; point < limit; point++ )
+ {
+ point->u = point->fx;
+ point->v = point->fy;
+ }
+ }
+ else
+ {
+ AF_Point point = hints->points;
+ AF_Point limit = point + hints->num_points;
+
+
+ for ( ; point < limit; point++ )
+ {
+ point->u = point->fy;
+ point->v = point->fx;
+ }
+ }
+
+ /* do each contour separately */
+ for ( ; contour < contour_limit; contour++ )
+ {
+ AF_Point point = contour[0];
+ AF_Point start = point;
+ AF_Point last = point->prev;
+
+
+ if ( point == last ) /* skip singletons -- just in case */
+ continue;
+
+ /* already on an edge ?, backtrack to find its start */
+ if ( FT_ABS( point->in_dir ) == major_dir )
+ {
+ point = point->prev;
+
+ while ( point->in_dir == start->in_dir )
+ point = point->prev;
+ }
+ else /* otherwise, find first segment start, if any */
+ {
+ while ( FT_ABS( point->out_dir ) != major_dir )
+ {
+ point = point->next;
+
+ if ( point == start )
+ goto NextContour;
+ }
+ }
+
+ start = point;
+
+ for (;;)
+ {
+ AF_Point first;
+ FT_Pos min_u, min_v, max_u, max_v;
+
+ /* we're at the start of a new segment */
+ FT_ASSERT( FT_ABS( point->out_dir ) == major_dir &&
+ point->in_dir != point->out_dir );
+ first = point;
+
+ min_u = max_u = point->u;
+ min_v = max_v = point->v;
+
+ point = point->next;
+
+ while ( point->out_dir == first->out_dir )
+ {
+ point = point->next;
+
+ if ( point->u < min_u )
+ min_u = point->u;
+
+ if ( point->u > max_u )
+ max_u = point->u;
+ }
+
+ if ( point->v < min_v )
+ min_v = point->v;
+
+ if ( point->v > max_v )
+ max_v = point->v;
+
+ /* record new segment */
+ error = af_axis_hints_new_segment( axis, memory, &segment );
+ if ( error )
+ goto Exit;
+
+ segment[0] = seg0;
+ segment->dir = first->out_dir;
+ segment->first = first;
+ segment->last = point;
+ segment->contour = contour;
+ segment->pos = (FT_Short)(( min_u + max_u ) >> 1);
+ segment->min_coord = (FT_Short) min_v;
+ segment->max_coord = (FT_Short) max_v;
+ segment->height = (FT_Short)(max_v - min_v);
+
+ /* a segment is round if it doesn't have successive */
+ /* on-curve points. */
+ {
+ AF_Point pt = first;
+ AF_Point last = point;
+ AF_Flags f0 = (AF_Flags)(pt->flags & AF_FLAG_CONTROL);
+ AF_Flags f1;
+
+
+ segment->flags &= ~AF_EDGE_ROUND;
+
+ for ( ; pt != last; f0 = f1 )
+ {
+ pt = pt->next;
+ f1 = (AF_Flags)(pt->flags & AF_FLAG_CONTROL);
+
+ if ( !f0 && !f1 )
+ break;
+
+ if ( pt == last )
+ segment->flags |= AF_EDGE_ROUND;
+ }
+ }
+
+ /* this can happen in the case of a degenerate contour
+ * e.g. a 2-point vertical contour
+ */
+ if ( point == start )
+ break;
+
+ /* jump to the start of the next segment, if any */
+ while ( FT_ABS(point->out_dir) != major_dir )
+ {
+ point = point->next;
+
+ if ( point == start )
+ goto NextContour;
+ }
+ }
+
+ NextContour:
+ ;
+ } /* contours */
+
+ /* now slightly increase the height of segments when this makes */
+ /* sense -- this is used to better detect and ignore serifs */
+ {
+ AF_Segment segments = axis->segments;
+ AF_Segment segments_end = segments + axis->num_segments;
+
+
+ for ( segment = segments; segment < segments_end; segment++ )
+ {
+ AF_Point first = segment->first;
+ AF_Point last = segment->last;
+ AF_Point p;
+ FT_Pos first_v = first->v;
+ FT_Pos last_v = last->v;
+
+
+ if ( first == last )
+ continue;
+
+ if ( first_v < last_v )
+ {
+ p = first->prev;
+ if ( p->v < first_v )
+ segment->height = (FT_Short)( segment->height +
+ ( ( first_v - p->v ) >> 1 ) );
+
+ p = last->next;
+ if ( p->v > last_v )
+ segment->height = (FT_Short)( segment->height +
+ ( ( p->v - last_v ) >> 1 ) );
+ }
+ else
+ {
+ p = first->prev;
+ if ( p->v > first_v )
+ segment->height = (FT_Short)( segment->height +
+ ( ( p->v - first_v ) >> 1 ) );
+
+ p = last->next;
+ if ( p->v < last_v )
+ segment->height = (FT_Short)( segment->height +
+ ( ( last_v - p->v ) >> 1 ) );
+ }
+ }
+ }
+
+#ifdef AF_SORT_SEGMENTS
+ /* place all segments with a negative direction to the start
+ * of the array, used to speed up segment linking later...
+ */
+ {
+ AF_Segment segments = axis->segments;
+ FT_UInt count = axis->num_segments;
+ FT_UInt ii, jj;
+
+ for (ii = 0; ii < count; ii++)
+ {
+ if ( segments[ii].dir > 0 )
+ {
+ for (jj = ii+1; jj < count; jj++)
+ {
+ if ( segments[jj].dir < 0 )
+ {
+ AF_SegmentRec tmp;
+
+ tmp = segments[ii];
+ segments[ii] = segments[jj];
+ segments[jj] = tmp;
+
+ break;
+ }
+ }
+
+ if ( jj == count )
+ break;
+ }
+ }
+ axis->mid_segments = ii;
+ }
+#endif
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_latin2_hints_link_segments( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_AxisHints axis = &hints->axis[dim];
+ AF_Segment segments = axis->segments;
+ AF_Segment segment_limit = segments + axis->num_segments;
+#ifdef AF_SORT_SEGMENTS
+ AF_Segment segment_mid = segments + axis->mid_segments;
+#endif
+ FT_Pos len_threshold, len_score;
+ AF_Segment seg1, seg2;
+
+
+ len_threshold = AF_LATIN_CONSTANT( hints->metrics, 8 );
+ if ( len_threshold == 0 )
+ len_threshold = 1;
+
+ len_score = AF_LATIN_CONSTANT( hints->metrics, 6000 );
+
+#ifdef AF_SORT_SEGMENTS
+ for ( seg1 = segments; seg1 < segment_mid; seg1++ )
+ {
+ if ( seg1->dir != axis->major_dir || seg1->first == seg1->last )
+ continue;
+
+ for ( seg2 = segment_mid; seg2 < segment_limit; seg2++ )
+#else
+ /* now compare each segment to the others */
+ for ( seg1 = segments; seg1 < segment_limit; seg1++ )
+ {
+ /* the fake segments are introduced to hint the metrics -- */
+ /* we must never link them to anything */
+ if ( seg1->dir != axis->major_dir || seg1->first == seg1->last )
+ continue;
+
+ for ( seg2 = segments; seg2 < segment_limit; seg2++ )
+ if ( seg1->dir + seg2->dir == 0 && seg2->pos > seg1->pos )
+#endif
+ {
+ FT_Pos pos1 = seg1->pos;
+ FT_Pos pos2 = seg2->pos;
+ FT_Pos dist = pos2 - pos1;
+
+
+ if ( dist < 0 )
+ continue;
+
+ {
+ FT_Pos min = seg1->min_coord;
+ FT_Pos max = seg1->max_coord;
+ FT_Pos len, score;
+
+
+ if ( min < seg2->min_coord )
+ min = seg2->min_coord;
+
+ if ( max > seg2->max_coord )
+ max = seg2->max_coord;
+
+ len = max - min;
+ if ( len >= len_threshold )
+ {
+ score = dist + len_score / len;
+ if ( score < seg1->score )
+ {
+ seg1->score = score;
+ seg1->link = seg2;
+ }
+
+ if ( score < seg2->score )
+ {
+ seg2->score = score;
+ seg2->link = seg1;
+ }
+ }
+ }
+ }
+ }
+#if 0
+ }
+#endif
+
+ /* now, compute the `serif' segments */
+ for ( seg1 = segments; seg1 < segment_limit; seg1++ )
+ {
+ seg2 = seg1->link;
+
+ if ( seg2 )
+ {
+ if ( seg2->link != seg1 )
+ {
+ seg1->link = 0;
+ seg1->serif = seg2->link;
+ }
+ }
+ }
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ af_latin2_hints_compute_edges( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_AxisHints axis = &hints->axis[dim];
+ FT_Error error = AF_Err_Ok;
+ FT_Memory memory = hints->memory;
+ AF_LatinAxis laxis = &((AF_LatinMetrics)hints->metrics)->axis[dim];
+
+ AF_Segment segments = axis->segments;
+ AF_Segment segment_limit = segments + axis->num_segments;
+ AF_Segment seg;
+
+ AF_Direction up_dir;
+ FT_Fixed scale;
+ FT_Pos edge_distance_threshold;
+ FT_Pos segment_length_threshold;
+
+
+ axis->num_edges = 0;
+
+ scale = ( dim == AF_DIMENSION_HORZ ) ? hints->x_scale
+ : hints->y_scale;
+
+ up_dir = ( dim == AF_DIMENSION_HORZ ) ? AF_DIR_UP
+ : AF_DIR_RIGHT;
+
+ /*
+ * We want to ignore very small (mostly serif) segments, we do that
+ * by ignoring those that whose length is less than a given fraction
+ * of the standard width. If there is no standard width, we ignore
+ * those that are less than a given size in pixels
+ *
+ * also, unlink serif segments that are linked to segments farther
+ * than 50% of the standard width
+ */
+ if ( dim == AF_DIMENSION_HORZ )
+ {
+ if ( laxis->width_count > 0 )
+ segment_length_threshold = (laxis->standard_width * 10 ) >> 4;
+ else
+ segment_length_threshold = FT_DivFix( 64, hints->y_scale );
+ }
+ else
+ segment_length_threshold = 0;
+
+ /*********************************************************************/
+ /* */
+ /* We will begin by generating a sorted table of edges for the */
+ /* current direction. To do so, we simply scan each segment and try */
+ /* to find an edge in our table that corresponds to its position. */
+ /* */
+ /* If no edge is found, we create and insert a new edge in the */
+ /* sorted table. Otherwise, we simply add the segment to the edge's */
+ /* list which will be processed in the second step to compute the */
+ /* edge's properties. */
+ /* */
+ /* Note that the edges table is sorted along the segment/edge */
+ /* position. */
+ /* */
+ /*********************************************************************/
+
+ edge_distance_threshold = FT_MulFix( laxis->edge_distance_threshold,
+ scale );
+ if ( edge_distance_threshold > 64 / 4 )
+ edge_distance_threshold = 64 / 4;
+
+ edge_distance_threshold = FT_DivFix( edge_distance_threshold,
+ scale );
+
+ for ( seg = segments; seg < segment_limit; seg++ )
+ {
+ AF_Edge found = 0;
+ FT_Int ee;
+
+
+ if ( seg->height < segment_length_threshold )
+ continue;
+
+ /* A special case for serif edges: If they are smaller than */
+ /* 1.5 pixels we ignore them. */
+ if ( seg->serif )
+ {
+ FT_Pos dist = seg->serif->pos - seg->pos;
+
+ if (dist < 0)
+ dist = -dist;
+
+ if (dist >= laxis->standard_width >> 1)
+ {
+ /* unlink this serif, it is too distant from its reference stem */
+ seg->serif = NULL;
+ }
+ else if ( 2*seg->height < 3 * segment_length_threshold )
+ continue;
+ }
+
+ /* look for an edge corresponding to the segment */
+ for ( ee = 0; ee < axis->num_edges; ee++ )
+ {
+ AF_Edge edge = axis->edges + ee;
+ FT_Pos dist;
+
+
+ dist = seg->pos - edge->fpos;
+ if ( dist < 0 )
+ dist = -dist;
+
+ if ( dist < edge_distance_threshold && edge->dir == seg->dir )
+ {
+ found = edge;
+ break;
+ }
+ }
+
+ if ( !found )
+ {
+ AF_Edge edge;
+
+
+ /* insert a new edge in the list and */
+ /* sort according to the position */
+ error = af_axis_hints_new_edge( axis, seg->pos, seg->dir, memory, &edge );
+ if ( error )
+ goto Exit;
+
+ /* add the segment to the new edge's list */
+ FT_ZERO( edge );
+
+ edge->first = seg;
+ edge->last = seg;
+ edge->fpos = seg->pos;
+ edge->dir = seg->dir;
+ edge->opos = edge->pos = FT_MulFix( seg->pos, scale );
+ seg->edge_next = seg;
+ }
+ else
+ {
+ /* if an edge was found, simply add the segment to the edge's */
+ /* list */
+ seg->edge_next = found->first;
+ found->last->edge_next = seg;
+ found->last = seg;
+ }
+ }
+
+
+ /*********************************************************************/
+ /* */
+ /* Good, we will now compute each edge's properties according to */
+ /* segments found on its position. Basically, these are: */
+ /* */
+ /* - edge's main direction */
+ /* - stem edge, serif edge or both (which defaults to stem then) */
+ /* - rounded edge, straight or both (which defaults to straight) */
+ /* - link for edge */
+ /* */
+ /*********************************************************************/
+
+ /* first of all, set the `edge' field in each segment -- this is */
+ /* required in order to compute edge links */
+
+ /*
+ * Note that removing this loop and setting the `edge' field of each
+ * segment directly in the code above slows down execution speed for
+ * some reasons on platforms like the Sun.
+ */
+ {
+ AF_Edge edges = axis->edges;
+ AF_Edge edge_limit = edges + axis->num_edges;
+ AF_Edge edge;
+
+
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ seg = edge->first;
+ if ( seg )
+ do
+ {
+ seg->edge = edge;
+ seg = seg->edge_next;
+
+ } while ( seg != edge->first );
+ }
+
+ /* now, compute each edge properties */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ FT_Int is_round = 0; /* does it contain round segments? */
+ FT_Int is_straight = 0; /* does it contain straight segments? */
+ FT_Pos ups = 0; /* number of upwards segments */
+ FT_Pos downs = 0; /* number of downwards segments */
+
+
+ seg = edge->first;
+
+ do
+ {
+ FT_Bool is_serif;
+
+
+ /* check for roundness of segment */
+ if ( seg->flags & AF_EDGE_ROUND )
+ is_round++;
+ else
+ is_straight++;
+
+ /* check for segment direction */
+ if ( seg->dir == up_dir )
+ ups += seg->max_coord-seg->min_coord;
+ else
+ downs += seg->max_coord-seg->min_coord;
+
+ /* check for links -- if seg->serif is set, then seg->link must */
+ /* be ignored */
+ is_serif = (FT_Bool)( seg->serif &&
+ seg->serif->edge &&
+ seg->serif->edge != edge );
+
+ if ( ( seg->link && seg->link->edge != NULL ) || is_serif )
+ {
+ AF_Edge edge2;
+ AF_Segment seg2;
+
+
+ edge2 = edge->link;
+ seg2 = seg->link;
+
+ if ( is_serif )
+ {
+ seg2 = seg->serif;
+ edge2 = edge->serif;
+ }
+
+ if ( edge2 )
+ {
+ FT_Pos edge_delta;
+ FT_Pos seg_delta;
+
+
+ edge_delta = edge->fpos - edge2->fpos;
+ if ( edge_delta < 0 )
+ edge_delta = -edge_delta;
+
+ seg_delta = seg->pos - seg2->pos;
+ if ( seg_delta < 0 )
+ seg_delta = -seg_delta;
+
+ if ( seg_delta < edge_delta )
+ edge2 = seg2->edge;
+ }
+ else
+ edge2 = seg2->edge;
+
+ if ( is_serif )
+ {
+ edge->serif = edge2;
+ edge2->flags |= AF_EDGE_SERIF;
+ }
+ else
+ edge->link = edge2;
+ }
+
+ seg = seg->edge_next;
+
+ } while ( seg != edge->first );
+
+ /* set the round/straight flags */
+ edge->flags = AF_EDGE_NORMAL;
+
+ if ( is_round > 0 && is_round >= is_straight )
+ edge->flags |= AF_EDGE_ROUND;
+
+#if 0
+ /* set the edge's main direction */
+ edge->dir = AF_DIR_NONE;
+
+ if ( ups > downs )
+ edge->dir = (FT_Char)up_dir;
+
+ else if ( ups < downs )
+ edge->dir = (FT_Char)-up_dir;
+
+ else if ( ups == downs )
+ edge->dir = 0; /* both up and down! */
+#endif
+
+ /* gets rid of serifs if link is set */
+ /* XXX: This gets rid of many unpleasant artefacts! */
+ /* Example: the `c' in cour.pfa at size 13 */
+
+ if ( edge->serif && edge->link )
+ edge->serif = 0;
+ }
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ af_latin2_hints_detect_features( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ FT_Error error;
+
+
+ error = af_latin2_hints_compute_segments( hints, dim );
+ if ( !error )
+ {
+ af_latin2_hints_link_segments( hints, dim );
+
+ error = af_latin2_hints_compute_edges( hints, dim );
+ }
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_latin2_hints_compute_blue_edges( AF_GlyphHints hints,
+ AF_LatinMetrics metrics )
+ {
+ AF_AxisHints axis = &hints->axis[ AF_DIMENSION_VERT ];
+ AF_Edge edge = axis->edges;
+ AF_Edge edge_limit = edge + axis->num_edges;
+ AF_LatinAxis latin = &metrics->axis[ AF_DIMENSION_VERT ];
+ FT_Fixed scale = latin->scale;
+ FT_Pos best_dist0; /* initial threshold */
+
+
+ /* compute the initial threshold as a fraction of the EM size */
+ best_dist0 = FT_MulFix( metrics->units_per_em / 40, scale );
+
+ if ( best_dist0 > 64 / 2 )
+ best_dist0 = 64 / 2;
+
+ /* compute which blue zones are active, i.e. have their scaled */
+ /* size < 3/4 pixels */
+
+ /* for each horizontal edge search the blue zone which is closest */
+ for ( ; edge < edge_limit; edge++ )
+ {
+ FT_Int bb;
+ AF_Width best_blue = NULL;
+ FT_Pos best_dist = best_dist0;
+
+ for ( bb = 0; bb < AF_LATIN_BLUE_MAX; bb++ )
+ {
+ AF_LatinBlue blue = latin->blues + bb;
+ FT_Bool is_top_blue, is_major_dir;
+
+
+ /* skip inactive blue zones (i.e., those that are too small) */
+ if ( !( blue->flags & AF_LATIN_BLUE_ACTIVE ) )
+ continue;
+
+ /* if it is a top zone, check for right edges -- if it is a bottom */
+ /* zone, check for left edges */
+ /* */
+ /* of course, that's for TrueType */
+ is_top_blue = (FT_Byte)( ( blue->flags & AF_LATIN_BLUE_TOP ) != 0 );
+ is_major_dir = FT_BOOL( edge->dir == axis->major_dir );
+
+ /* if it is a top zone, the edge must be against the major */
+ /* direction; if it is a bottom zone, it must be in the major */
+ /* direction */
+ if ( is_top_blue ^ is_major_dir )
+ {
+ FT_Pos dist;
+ AF_Width compare;
+
+
+ /* if it's a rounded edge, compare it to the overshoot position */
+ /* if it's a flat edge, compare it to the reference position */
+ if ( edge->flags & AF_EDGE_ROUND )
+ compare = &blue->shoot;
+ else
+ compare = &blue->ref;
+
+ dist = edge->fpos - compare->org;
+ if (dist < 0)
+ dist = -dist;
+
+ dist = FT_MulFix( dist, scale );
+ if ( dist < best_dist )
+ {
+ best_dist = dist;
+ best_blue = compare;
+ }
+
+#if 0
+ /* now, compare it to the overshoot position if the edge is */
+ /* rounded, and if the edge is over the reference position of a */
+ /* top zone, or under the reference position of a bottom zone */
+ if ( edge->flags & AF_EDGE_ROUND && dist != 0 )
+ {
+ FT_Bool is_under_ref = FT_BOOL( edge->fpos < blue->ref.org );
+
+
+ if ( is_top_blue ^ is_under_ref )
+ {
+ blue = latin->blues + bb;
+ dist = edge->fpos - blue->shoot.org;
+ if ( dist < 0 )
+ dist = -dist;
+
+ dist = FT_MulFix( dist, scale );
+ if ( dist < best_dist )
+ {
+ best_dist = dist;
+ best_blue = & blue->shoot;
+ }
+ }
+ }
+#endif
+ }
+ }
+
+ if ( best_blue )
+ edge->blue_edge = best_blue;
+ }
+ }
+
+
+ static FT_Error
+ af_latin2_hints_init( AF_GlyphHints hints,
+ AF_LatinMetrics metrics )
+ {
+ FT_Render_Mode mode;
+ FT_UInt32 scaler_flags, other_flags;
+ FT_Face face = metrics->root.scaler.face;
+
+
+ af_glyph_hints_rescale( hints, (AF_ScriptMetrics)metrics );
+
+ /*
+ * correct x_scale and y_scale if needed, since they may have
+ * been modified `af_latin2_metrics_scale_dim' above
+ */
+ hints->x_scale = metrics->axis[AF_DIMENSION_HORZ].scale;
+ hints->x_delta = metrics->axis[AF_DIMENSION_HORZ].delta;
+ hints->y_scale = metrics->axis[AF_DIMENSION_VERT].scale;
+ hints->y_delta = metrics->axis[AF_DIMENSION_VERT].delta;
+
+ /* compute flags depending on render mode, etc. */
+ mode = metrics->root.scaler.render_mode;
+
+#if 0 /* #ifdef AF_USE_WARPER */
+ if ( mode == FT_RENDER_MODE_LCD || mode == FT_RENDER_MODE_LCD_V )
+ {
+ metrics->root.scaler.render_mode = mode = FT_RENDER_MODE_NORMAL;
+ }
+#endif
+
+ scaler_flags = hints->scaler_flags;
+ other_flags = 0;
+
+ /*
+ * We snap the width of vertical stems for the monochrome and
+ * horizontal LCD rendering targets only.
+ */
+ if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD )
+ other_flags |= AF_LATIN_HINTS_HORZ_SNAP;
+
+ /*
+ * We snap the width of horizontal stems for the monochrome and
+ * vertical LCD rendering targets only.
+ */
+ if ( mode == FT_RENDER_MODE_MONO || mode == FT_RENDER_MODE_LCD_V )
+ other_flags |= AF_LATIN_HINTS_VERT_SNAP;
+
+ /*
+ * We adjust stems to full pixels only if we don't use the `light' mode.
+ */
+ if ( mode != FT_RENDER_MODE_LIGHT )
+ other_flags |= AF_LATIN_HINTS_STEM_ADJUST;
+
+ if ( mode == FT_RENDER_MODE_MONO )
+ other_flags |= AF_LATIN_HINTS_MONO;
+
+ /*
+ * In `light' hinting mode we disable horizontal hinting completely.
+ * We also do it if the face is italic.
+ */
+ if ( mode == FT_RENDER_MODE_LIGHT ||
+ (face->style_flags & FT_STYLE_FLAG_ITALIC) != 0 )
+ scaler_flags |= AF_SCALER_FLAG_NO_HORIZONTAL;
+
+ hints->scaler_flags = scaler_flags;
+ hints->other_flags = other_flags;
+
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** L A T I N G L Y P H G R I D - F I T T I N G *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* snap a given width in scaled coordinates to one of the */
+ /* current standard widths */
+
+ static FT_Pos
+ af_latin2_snap_width( AF_Width widths,
+ FT_Int count,
+ FT_Pos width )
+ {
+ int n;
+ FT_Pos best = 64 + 32 + 2;
+ FT_Pos reference = width;
+ FT_Pos scaled;
+
+
+ for ( n = 0; n < count; n++ )
+ {
+ FT_Pos w;
+ FT_Pos dist;
+
+
+ w = widths[n].cur;
+ dist = width - w;
+ if ( dist < 0 )
+ dist = -dist;
+ if ( dist < best )
+ {
+ best = dist;
+ reference = w;
+ }
+ }
+
+ scaled = FT_PIX_ROUND( reference );
+
+ if ( width >= reference )
+ {
+ if ( width < scaled + 48 )
+ width = reference;
+ }
+ else
+ {
+ if ( width > scaled - 48 )
+ width = reference;
+ }
+
+ return width;
+ }
+
+
+ /* compute the snapped width of a given stem */
+
+ static FT_Pos
+ af_latin2_compute_stem_width( AF_GlyphHints hints,
+ AF_Dimension dim,
+ FT_Pos width,
+ AF_Edge_Flags base_flags,
+ AF_Edge_Flags stem_flags )
+ {
+ AF_LatinMetrics metrics = (AF_LatinMetrics) hints->metrics;
+ AF_LatinAxis axis = & metrics->axis[dim];
+ FT_Pos dist = width;
+ FT_Int sign = 0;
+ FT_Int vertical = ( dim == AF_DIMENSION_VERT );
+
+
+ FT_UNUSED(base_flags);
+
+ if ( !AF_LATIN_HINTS_DO_STEM_ADJUST( hints ) ||
+ axis->extra_light )
+ return width;
+
+ if ( dist < 0 )
+ {
+ dist = -width;
+ sign = 1;
+ }
+
+ if ( ( vertical && !AF_LATIN_HINTS_DO_VERT_SNAP( hints ) ) ||
+ ( !vertical && !AF_LATIN_HINTS_DO_HORZ_SNAP( hints ) ) )
+ {
+ /* smooth hinting process: very lightly quantize the stem width */
+
+ /* leave the widths of serifs alone */
+
+ if ( ( stem_flags & AF_EDGE_SERIF ) && vertical && ( dist < 3 * 64 ) )
+ goto Done_Width;
+
+#if 0
+ else if ( ( base_flags & AF_EDGE_ROUND ) )
+ {
+ if ( dist < 80 )
+ dist = 64;
+ }
+ else if ( dist < 56 )
+ dist = 56;
+#endif
+ if ( axis->width_count > 0 )
+ {
+ FT_Pos delta;
+
+
+ /* compare to standard width */
+ if ( axis->width_count > 0 )
+ {
+ delta = dist - axis->widths[0].cur;
+
+ if ( delta < 0 )
+ delta = -delta;
+
+ if ( delta < 40 )
+ {
+ dist = axis->widths[0].cur;
+ if ( dist < 48 )
+ dist = 48;
+
+ goto Done_Width;
+ }
+ }
+
+ if ( dist < 3 * 64 )
+ {
+ delta = dist & 63;
+ dist &= -64;
+
+ if ( delta < 10 )
+ dist += delta;
+
+ else if ( delta < 32 )
+ dist += 10;
+
+ else if ( delta < 54 )
+ dist += 54;
+
+ else
+ dist += delta;
+ }
+ else
+ dist = ( dist + 32 ) & ~63;
+ }
+ }
+ else
+ {
+ /* strong hinting process: snap the stem width to integer pixels */
+ FT_Pos org_dist = dist;
+
+
+ dist = af_latin2_snap_width( axis->widths, axis->width_count, dist );
+
+ if ( vertical )
+ {
+ /* in the case of vertical hinting, always round */
+ /* the stem heights to integer pixels */
+
+ if ( dist >= 64 )
+ dist = ( dist + 16 ) & ~63;
+ else
+ dist = 64;
+ }
+ else
+ {
+ if ( AF_LATIN_HINTS_DO_MONO( hints ) )
+ {
+ /* monochrome horizontal hinting: snap widths to integer pixels */
+ /* with a different threshold */
+
+ if ( dist < 64 )
+ dist = 64;
+ else
+ dist = ( dist + 32 ) & ~63;
+ }
+ else
+ {
+ /* for horizontal anti-aliased hinting, we adopt a more subtle */
+ /* approach: we strengthen small stems, round stems whose size */
+ /* is between 1 and 2 pixels to an integer, otherwise nothing */
+
+ if ( dist < 48 )
+ dist = ( dist + 64 ) >> 1;
+
+ else if ( dist < 128 )
+ {
+ /* We only round to an integer width if the corresponding */
+ /* distortion is less than 1/4 pixel. Otherwise this */
+ /* makes everything worse since the diagonals, which are */
+ /* not hinted, appear a lot bolder or thinner than the */
+ /* vertical stems. */
+
+ FT_Int delta;
+
+
+ dist = ( dist + 22 ) & ~63;
+ delta = dist - org_dist;
+ if ( delta < 0 )
+ delta = -delta;
+
+ if (delta >= 16)
+ {
+ dist = org_dist;
+ if ( dist < 48 )
+ dist = ( dist + 64 ) >> 1;
+ }
+ }
+ else
+ /* round otherwise to prevent color fringes in LCD mode */
+ dist = ( dist + 32 ) & ~63;
+ }
+ }
+ }
+
+ Done_Width:
+ if ( sign )
+ dist = -dist;
+
+ return dist;
+ }
+
+
+ /* align one stem edge relative to the previous stem edge */
+
+ static void
+ af_latin2_align_linked_edge( AF_GlyphHints hints,
+ AF_Dimension dim,
+ AF_Edge base_edge,
+ AF_Edge stem_edge )
+ {
+ FT_Pos dist = stem_edge->opos - base_edge->opos;
+
+ FT_Pos fitted_width = af_latin2_compute_stem_width(
+ hints, dim, dist,
+ (AF_Edge_Flags)base_edge->flags,
+ (AF_Edge_Flags)stem_edge->flags );
+
+
+ stem_edge->pos = base_edge->pos + fitted_width;
+
+ AF_LOG(( "LINK: edge %d (opos=%.2f) linked to (%.2f), "
+ "dist was %.2f, now %.2f\n",
+ stem_edge-hints->axis[dim].edges, stem_edge->opos / 64.0,
+ stem_edge->pos / 64.0, dist / 64.0, fitted_width / 64.0 ));
+ }
+
+
+ static void
+ af_latin2_align_serif_edge( AF_GlyphHints hints,
+ AF_Edge base,
+ AF_Edge serif )
+ {
+ FT_UNUSED( hints );
+
+ serif->pos = base->pos + (serif->opos - base->opos);
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** E D G E H I N T I N G ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_LOCAL_DEF( void )
+ af_latin2_hint_edges( AF_GlyphHints hints,
+ AF_Dimension dim )
+ {
+ AF_AxisHints axis = &hints->axis[dim];
+ AF_Edge edges = axis->edges;
+ AF_Edge edge_limit = edges + axis->num_edges;
+ FT_Int n_edges;
+ AF_Edge edge;
+ AF_Edge anchor = 0;
+ FT_Int has_serifs = 0;
+ FT_Pos anchor_drift = 0;
+
+
+
+ AF_LOG(( "==== hinting %s edges =====\n", dim == AF_DIMENSION_HORZ ? "vertical" : "horizontal" ));
+
+ /* we begin by aligning all stems relative to the blue zone */
+ /* if needed -- that's only for horizontal edges */
+
+ if ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_BLUES( hints ) )
+ {
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ AF_Width blue;
+ AF_Edge edge1, edge2;
+
+
+ if ( edge->flags & AF_EDGE_DONE )
+ continue;
+
+ blue = edge->blue_edge;
+ edge1 = NULL;
+ edge2 = edge->link;
+
+ if ( blue )
+ {
+ edge1 = edge;
+ }
+ else if ( edge2 && edge2->blue_edge )
+ {
+ blue = edge2->blue_edge;
+ edge1 = edge2;
+ edge2 = edge;
+ }
+
+ if ( !edge1 )
+ continue;
+
+ AF_LOG(( "BLUE: edge %d (opos=%.2f) snapped to (%.2f), "
+ "was (%.2f)\n",
+ edge1-edges, edge1->opos / 64.0, blue->fit / 64.0,
+ edge1->pos / 64.0 ));
+
+ edge1->pos = blue->fit;
+ edge1->flags |= AF_EDGE_DONE;
+
+ if ( edge2 && !edge2->blue_edge )
+ {
+ af_latin2_align_linked_edge( hints, dim, edge1, edge2 );
+ edge2->flags |= AF_EDGE_DONE;
+ }
+
+ if ( !anchor )
+ {
+ anchor = edge;
+
+ anchor_drift = (anchor->pos - anchor->opos);
+ if (edge2)
+ anchor_drift = (anchor_drift + (edge2->pos - edge2->opos)) >> 1;
+ }
+ }
+ }
+
+ /* now we will align all stem edges, trying to maintain the */
+ /* relative order of stems in the glyph */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ AF_Edge edge2;
+
+
+ if ( edge->flags & AF_EDGE_DONE )
+ continue;
+
+ /* skip all non-stem edges */
+ edge2 = edge->link;
+ if ( !edge2 )
+ {
+ has_serifs++;
+ continue;
+ }
+
+ /* now align the stem */
+
+ /* this should not happen, but it's better to be safe */
+ if ( edge2->blue_edge )
+ {
+ AF_LOG(( "ASSERTION FAILED for edge %d\n", edge2-edges ));
+
+ af_latin2_align_linked_edge( hints, dim, edge2, edge );
+ edge->flags |= AF_EDGE_DONE;
+ continue;
+ }
+
+ if ( !anchor )
+ {
+ FT_Pos org_len, org_center, cur_len;
+ FT_Pos cur_pos1, error1, error2, u_off, d_off;
+
+
+ org_len = edge2->opos - edge->opos;
+ cur_len = af_latin2_compute_stem_width(
+ hints, dim, org_len,
+ (AF_Edge_Flags)edge->flags,
+ (AF_Edge_Flags)edge2->flags );
+ if ( cur_len <= 64 )
+ u_off = d_off = 32;
+ else
+ {
+ u_off = 38;
+ d_off = 26;
+ }
+
+ if ( cur_len < 96 )
+ {
+ org_center = edge->opos + ( org_len >> 1 );
+
+ cur_pos1 = FT_PIX_ROUND( org_center );
+
+ error1 = org_center - ( cur_pos1 - u_off );
+ if ( error1 < 0 )
+ error1 = -error1;
+
+ error2 = org_center - ( cur_pos1 + d_off );
+ if ( error2 < 0 )
+ error2 = -error2;
+
+ if ( error1 < error2 )
+ cur_pos1 -= u_off;
+ else
+ cur_pos1 += d_off;
+
+ edge->pos = cur_pos1 - cur_len / 2;
+ edge2->pos = edge->pos + cur_len;
+ }
+ else
+ edge->pos = FT_PIX_ROUND( edge->opos );
+
+ AF_LOG(( "ANCHOR: edge %d (opos=%.2f) and %d (opos=%.2f) "
+ "snapped to (%.2f) (%.2f)\n",
+ edge-edges, edge->opos / 64.0,
+ edge2-edges, edge2->opos / 64.0,
+ edge->pos / 64.0, edge2->pos / 64.0 ));
+ anchor = edge;
+
+ edge->flags |= AF_EDGE_DONE;
+
+ af_latin2_align_linked_edge( hints, dim, edge, edge2 );
+
+ edge2->flags |= AF_EDGE_DONE;
+
+ anchor_drift = ( (anchor->pos - anchor->opos) +
+ (edge2->pos - edge2->opos)) >> 1;
+
+ AF_LOG(( "DRIFT: %.2f\n", anchor_drift/64.0 ));
+ }
+ else
+ {
+ FT_Pos org_pos, org_len, org_center, cur_center, cur_len;
+ FT_Pos org_left, org_right;
+
+
+ org_pos = edge->opos + anchor_drift;
+ org_len = edge2->opos - edge->opos;
+ org_center = org_pos + ( org_len >> 1 );
+
+ cur_len = af_latin2_compute_stem_width(
+ hints, dim, org_len,
+ (AF_Edge_Flags)edge->flags,
+ (AF_Edge_Flags)edge2->flags );
+
+ org_left = org_pos + ((org_len - cur_len) >> 1);
+ org_right = org_pos + ((org_len + cur_len) >> 1);
+
+ AF_LOG(( "ALIGN: left=%.2f right=%.2f ", org_left/64.0, org_right/64.0 ));
+ cur_center = org_center;
+
+ if ( edge2->flags & AF_EDGE_DONE )
+ {
+ AF_LOG(( "\n" ));
+ edge->pos = edge2->pos - cur_len;
+ }
+ else
+ {
+ /* we want to compare several displacement, and choose
+ * the one that increases fitness while minimizing
+ * distortion as well
+ */
+ FT_Pos displacements[6], scores[6], org, fit, delta;
+ FT_UInt count = 0;
+
+ /* note: don't even try to fit tiny stems */
+ if ( cur_len < 32 )
+ {
+ AF_LOG(( "tiny stem\n" ));
+ goto AlignStem;
+ }
+
+ /* if the span is within a single pixel, don't touch it */
+ if ( FT_PIX_FLOOR(org_left) == FT_PIX_CEIL(org_right) )
+ {
+ AF_LOG(( "single pixel stem\n" ));
+ goto AlignStem;
+ }
+
+ if (cur_len <= 96)
+ {
+ /* we want to avoid the absolute worst case which is
+ * when the left and right edges of the span each represent
+ * about 50% of the gray. we'd better want to change this
+ * to 25/75%, since this is much more pleasant to the eye with
+ * very acceptable distortion
+ */
+ FT_Pos frac_left = (org_left) & 63;
+ FT_Pos frac_right = (org_right) & 63;
+
+ if ( frac_left >= 22 && frac_left <= 42 &&
+ frac_right >= 22 && frac_right <= 42 )
+ {
+ org = frac_left;
+ fit = (org <= 32) ? 16 : 48;
+ delta = FT_ABS(fit - org);
+ displacements[count] = fit - org;
+ scores[count++] = delta;
+ AF_LOG(( "dispA=%.2f (%d) ", (fit - org)/64.0, delta ));
+
+ org = frac_right;
+ fit = (org <= 32) ? 16 : 48;
+ delta = FT_ABS(fit - org);
+ displacements[count] = fit - org;
+ scores[count++] = delta;
+ AF_LOG(( "dispB=%.2f (%d) ", (fit - org)/64.0, delta ));
+ }
+ }
+
+ /* snapping the left edge to the grid */
+ org = org_left;
+ fit = FT_PIX_ROUND(org);
+ delta = FT_ABS(fit - org);
+ displacements[count] = fit - org;
+ scores[count++] = delta;
+ AF_LOG(( "dispC=%.2f (%d) ", (fit - org)/64.0, delta ));
+
+ /* snapping the right edge to the grid */
+ org = org_right;
+ fit = FT_PIX_ROUND(org);
+ delta = FT_ABS(fit - org);
+ displacements[count] = fit - org;
+ scores[count++] = delta;
+ AF_LOG(( "dispD=%.2f (%d) ", (fit - org)/64.0, delta ));
+
+ /* now find the best displacement */
+ {
+ FT_Pos best_score = scores[0];
+ FT_Pos best_disp = displacements[0];
+ FT_UInt nn;
+
+ for (nn = 1; nn < count; nn++)
+ {
+ if (scores[nn] < best_score)
+ {
+ best_score = scores[nn];
+ best_disp = displacements[nn];
+ }
+ }
+
+ cur_center = org_center + best_disp;
+ }
+ AF_LOG(( "\n" ));
+ }
+
+ AlignStem:
+ edge->pos = cur_center - (cur_len >> 1);
+ edge2->pos = edge->pos + cur_len;
+
+ AF_LOG(( "STEM1: %d (opos=%.2f) to %d (opos=%.2f) "
+ "snapped to (%.2f) and (%.2f), org_len = %.2f cur_len=%.2f\n",
+ edge-edges, edge->opos / 64.0,
+ edge2-edges, edge2->opos / 64.0,
+ edge->pos / 64.0, edge2->pos / 64.0,
+ org_len / 64.0, cur_len / 64.0 ));
+
+ edge->flags |= AF_EDGE_DONE;
+ edge2->flags |= AF_EDGE_DONE;
+
+ if ( edge > edges && edge->pos < edge[-1].pos )
+ {
+ AF_LOG(( "BOUND: %d (pos=%.2f) to (%.2f)\n",
+ edge-edges, edge->pos / 64.0, edge[-1].pos / 64.0 ));
+ edge->pos = edge[-1].pos;
+ }
+ }
+ }
+
+ /* make sure that lowercase m's maintain their symmetry */
+
+ /* In general, lowercase m's have six vertical edges if they are sans */
+ /* serif, or twelve if they are with serifs. This implementation is */
+ /* based on that assumption, and seems to work very well with most */
+ /* faces. However, if for a certain face this assumption is not */
+ /* true, the m is just rendered like before. In addition, any stem */
+ /* correction will only be applied to symmetrical glyphs (even if the */
+ /* glyph is not an m), so the potential for unwanted distortion is */
+ /* relatively low. */
+
+ /* We don't handle horizontal edges since we can't easily assure that */
+ /* the third (lowest) stem aligns with the base line; it might end up */
+ /* one pixel higher or lower. */
+#if 0
+ n_edges = edge_limit - edges;
+ if ( dim == AF_DIMENSION_HORZ && ( n_edges == 6 || n_edges == 12 ) )
+ {
+ AF_Edge edge1, edge2, edge3;
+ FT_Pos dist1, dist2, span, delta;
+
+
+ if ( n_edges == 6 )
+ {
+ edge1 = edges;
+ edge2 = edges + 2;
+ edge3 = edges + 4;
+ }
+ else
+ {
+ edge1 = edges + 1;
+ edge2 = edges + 5;
+ edge3 = edges + 9;
+ }
+
+ dist1 = edge2->opos - edge1->opos;
+ dist2 = edge3->opos - edge2->opos;
+
+ span = dist1 - dist2;
+ if ( span < 0 )
+ span = -span;
+
+ if ( span < 8 )
+ {
+ delta = edge3->pos - ( 2 * edge2->pos - edge1->pos );
+ edge3->pos -= delta;
+ if ( edge3->link )
+ edge3->link->pos -= delta;
+
+ /* move the serifs along with the stem */
+ if ( n_edges == 12 )
+ {
+ ( edges + 8 )->pos -= delta;
+ ( edges + 11 )->pos -= delta;
+ }
+
+ edge3->flags |= AF_EDGE_DONE;
+ if ( edge3->link )
+ edge3->link->flags |= AF_EDGE_DONE;
+ }
+ }
+#endif
+ if ( has_serifs || !anchor )
+ {
+ /*
+ * now hint the remaining edges (serifs and single) in order
+ * to complete our processing
+ */
+ for ( edge = edges; edge < edge_limit; edge++ )
+ {
+ FT_Pos delta;
+
+
+ if ( edge->flags & AF_EDGE_DONE )
+ continue;
+
+ delta = 1000;
+
+ if ( edge->serif )
+ {
+ delta = edge->serif->opos - edge->opos;
+ if ( delta < 0 )
+ delta = -delta;
+ }
+
+ if ( delta < 64 + 16 )
+ {
+ af_latin2_align_serif_edge( hints, edge->serif, edge );
+ AF_LOG(( "SERIF: edge %d (opos=%.2f) serif to %d (opos=%.2f) "
+ "aligned to (%.2f)\n",
+ edge-edges, edge->opos / 64.0,
+ edge->serif - edges, edge->serif->opos / 64.0,
+ edge->pos / 64.0 ));
+ }
+ else if ( !anchor )
+ {
+ AF_LOG(( "SERIF_ANCHOR: edge %d (opos=%.2f) snapped to (%.2f)\n",
+ edge-edges, edge->opos / 64.0, edge->pos / 64.0 ));
+ edge->pos = FT_PIX_ROUND( edge->opos );
+ anchor = edge;
+ }
+ else
+ {
+ AF_Edge before, after;
+
+
+ for ( before = edge - 1; before >= edges; before-- )
+ if ( before->flags & AF_EDGE_DONE )
+ break;
+
+ for ( after = edge + 1; after < edge_limit; after++ )
+ if ( after->flags & AF_EDGE_DONE )
+ break;
+
+ if ( before >= edges && before < edge &&
+ after < edge_limit && after > edge )
+ {
+ if ( after->opos == before->opos )
+ edge->pos = before->pos;
+ else
+ edge->pos = before->pos +
+ FT_MulDiv( edge->opos - before->opos,
+ after->pos - before->pos,
+ after->opos - before->opos );
+ AF_LOG(( "SERIF_LINK1: edge %d (opos=%.2f) snapped to (%.2f) from %d (opos=%.2f)\n",
+ edge-edges, edge->opos / 64.0, edge->pos / 64.0, before - edges, before->opos / 64.0 ));
+ }
+ else
+ {
+ edge->pos = anchor->pos + (( edge->opos - anchor->opos + 16) & ~31);
+
+ AF_LOG(( "SERIF_LINK2: edge %d (opos=%.2f) snapped to (%.2f)\n",
+ edge-edges, edge->opos / 64.0, edge->pos / 64.0 ));
+ }
+ }
+
+ edge->flags |= AF_EDGE_DONE;
+
+ if ( edge > edges && edge->pos < edge[-1].pos )
+ edge->pos = edge[-1].pos;
+
+ if ( edge + 1 < edge_limit &&
+ edge[1].flags & AF_EDGE_DONE &&
+ edge->pos > edge[1].pos )
+ edge->pos = edge[1].pos;
+ }
+ }
+ }
+
+
+ static FT_Error
+ af_latin2_hints_apply( AF_GlyphHints hints,
+ FT_Outline* outline,
+ AF_LatinMetrics metrics )
+ {
+ FT_Error error;
+ int dim;
+
+
+ error = af_glyph_hints_reload( hints, outline, 1 );
+ if ( error )
+ goto Exit;
+
+ /* analyze glyph outline */
+#ifdef AF_USE_WARPER
+ if ( metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT ||
+ AF_HINTS_DO_HORIZONTAL( hints ) )
+#else
+ if ( AF_HINTS_DO_HORIZONTAL( hints ) )
+#endif
+ {
+ error = af_latin2_hints_detect_features( hints, AF_DIMENSION_HORZ );
+ if ( error )
+ goto Exit;
+ }
+
+ if ( AF_HINTS_DO_VERTICAL( hints ) )
+ {
+ error = af_latin2_hints_detect_features( hints, AF_DIMENSION_VERT );
+ if ( error )
+ goto Exit;
+
+ af_latin2_hints_compute_blue_edges( hints, metrics );
+ }
+
+ /* grid-fit the outline */
+ for ( dim = 0; dim < AF_DIMENSION_MAX; dim++ )
+ {
+#ifdef AF_USE_WARPER
+ if ( ( dim == AF_DIMENSION_HORZ &&
+ metrics->root.scaler.render_mode == FT_RENDER_MODE_LIGHT ) )
+ {
+ AF_WarperRec warper;
+ FT_Fixed scale;
+ FT_Pos delta;
+
+
+ af_warper_compute( &warper, hints, dim, &scale, &delta );
+ af_glyph_hints_scale_dim( hints, dim, scale, delta );
+ continue;
+ }
+#endif
+
+ if ( ( dim == AF_DIMENSION_HORZ && AF_HINTS_DO_HORIZONTAL( hints ) ) ||
+ ( dim == AF_DIMENSION_VERT && AF_HINTS_DO_VERTICAL( hints ) ) )
+ {
+ af_latin2_hint_edges( hints, (AF_Dimension)dim );
+ af_glyph_hints_align_edge_points( hints, (AF_Dimension)dim );
+ af_glyph_hints_align_strong_points( hints, (AF_Dimension)dim );
+ af_glyph_hints_align_weak_points( hints, (AF_Dimension)dim );
+ }
+ }
+ af_glyph_hints_save( hints, outline );
+
+ Exit:
+ return error;
+ }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** L A T I N S C R I P T C L A S S *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ static const AF_Script_UniRangeRec af_latin2_uniranges[] =
+ {
+ { 32, 127 }, /* XXX: TODO: Add new Unicode ranges here! */
+ { 160, 255 },
+ { 0, 0 }
+ };
+
+
+ FT_CALLBACK_TABLE_DEF const AF_ScriptClassRec
+ af_latin2_script_class =
+ {
+ AF_SCRIPT_LATIN2,
+ af_latin2_uniranges,
+
+ sizeof( AF_LatinMetricsRec ),
+
+ (AF_Script_InitMetricsFunc) af_latin2_metrics_init,
+ (AF_Script_ScaleMetricsFunc)af_latin2_metrics_scale,
+ (AF_Script_DoneMetricsFunc) NULL,
+
+ (AF_Script_InitHintsFunc) af_latin2_hints_init,
+ (AF_Script_ApplyHintsFunc) af_latin2_hints_apply
+ };
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/aflatin2.h b/src/3rdparty/freetype/src/autofit/aflatin2.h
new file mode 100644
index 0000000000..34eda05822
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/aflatin2.h
@@ -0,0 +1,40 @@
+/***************************************************************************/
+/* */
+/* aflatin2.h */
+/* */
+/* Auto-fitter hinting routines for latin script (specification). */
+/* */
+/* Copyright 2003, 2004, 2005, 2006, 2007 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AFLATIN2_H__
+#define __AFLATIN2_H__
+
+#include "afhints.h"
+
+
+FT_BEGIN_HEADER
+
+
+ /* the latin-specific script class */
+
+ FT_CALLBACK_TABLE const AF_ScriptClassRec
+ af_latin2_script_class;
+
+/* */
+
+FT_END_HEADER
+
+#endif /* __AFLATIN_H__ */
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/afloader.c b/src/3rdparty/freetype/src/autofit/afloader.c
new file mode 100644
index 0000000000..4e48c2fe97
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/afloader.c
@@ -0,0 +1,535 @@
+/***************************************************************************/
+/* */
+/* afloader.c */
+/* */
+/* Auto-fitter glyph loading routines (body). */
+/* */
+/* Copyright 2003, 2004, 2005, 2006, 2007, 2008 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "afloader.h"
+#include "afhints.h"
+#include "afglobal.h"
+#include "aflatin.h"
+#include "aferrors.h"
+
+
+ FT_LOCAL_DEF( FT_Error )
+ af_loader_init( AF_Loader loader,
+ FT_Memory memory )
+ {
+ FT_ZERO( loader );
+
+ af_glyph_hints_init( &loader->hints, memory );
+#ifdef AF_DEBUG
+ _af_debug_hints = &loader->hints;
+#endif
+ return FT_GlyphLoader_New( memory, &loader->gloader );
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ af_loader_reset( AF_Loader loader,
+ FT_Face face )
+ {
+ FT_Error error = AF_Err_Ok;
+
+
+ loader->face = face;
+ loader->globals = (AF_FaceGlobals)face->autohint.data;
+
+ FT_GlyphLoader_Rewind( loader->gloader );
+
+ if ( loader->globals == NULL )
+ {
+ error = af_face_globals_new( face, &loader->globals );
+ if ( !error )
+ {
+ face->autohint.data =
+ (FT_Pointer)loader->globals;
+ face->autohint.finalizer =
+ (FT_Generic_Finalizer)af_face_globals_free;
+ }
+ }
+
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_loader_done( AF_Loader loader )
+ {
+ af_glyph_hints_done( &loader->hints );
+
+ loader->face = NULL;
+ loader->globals = NULL;
+
+#ifdef AF_DEBUG
+ _af_debug_hints = NULL;
+#endif
+ FT_GlyphLoader_Done( loader->gloader );
+ loader->gloader = NULL;
+ }
+
+
+ static FT_Error
+ af_loader_load_g( AF_Loader loader,
+ AF_Scaler scaler,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags,
+ FT_UInt depth )
+ {
+ FT_Error error;
+ FT_Face face = loader->face;
+ FT_GlyphLoader gloader = loader->gloader;
+ AF_ScriptMetrics metrics = loader->metrics;
+ AF_GlyphHints hints = &loader->hints;
+ FT_GlyphSlot slot = face->glyph;
+ FT_Slot_Internal internal = slot->internal;
+
+
+ error = FT_Load_Glyph( face, glyph_index, load_flags );
+ if ( error )
+ goto Exit;
+
+ loader->transformed = internal->glyph_transformed;
+ if ( loader->transformed )
+ {
+ FT_Matrix inverse;
+
+
+ loader->trans_matrix = internal->glyph_matrix;
+ loader->trans_delta = internal->glyph_delta;
+
+ inverse = loader->trans_matrix;
+ FT_Matrix_Invert( &inverse );
+ FT_Vector_Transform( &loader->trans_delta, &inverse );
+ }
+
+ /* set linear metrics */
+ slot->linearHoriAdvance = slot->metrics.horiAdvance;
+ slot->linearVertAdvance = slot->metrics.vertAdvance;
+
+ switch ( slot->format )
+ {
+ case FT_GLYPH_FORMAT_OUTLINE:
+ /* translate the loaded glyph when an internal transform is needed */
+ if ( loader->transformed )
+ FT_Outline_Translate( &slot->outline,
+ loader->trans_delta.x,
+ loader->trans_delta.y );
+
+ /* copy the outline points in the loader's current */
+ /* extra points which is used to keep original glyph coordinates */
+ error = FT_GLYPHLOADER_CHECK_POINTS( gloader,
+ slot->outline.n_points + 4,
+ slot->outline.n_contours );
+ if ( error )
+ goto Exit;
+
+ FT_ARRAY_COPY( gloader->current.outline.points,
+ slot->outline.points,
+ slot->outline.n_points );
+
+ FT_ARRAY_COPY( gloader->current.outline.contours,
+ slot->outline.contours,
+ slot->outline.n_contours );
+
+ FT_ARRAY_COPY( gloader->current.outline.tags,
+ slot->outline.tags,
+ slot->outline.n_points );
+
+ gloader->current.outline.n_points = slot->outline.n_points;
+ gloader->current.outline.n_contours = slot->outline.n_contours;
+
+ /* compute original horizontal phantom points (and ignore */
+ /* vertical ones) */
+ loader->pp1.x = hints->x_delta;
+ loader->pp1.y = hints->y_delta;
+ loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance,
+ hints->x_scale ) + hints->x_delta;
+ loader->pp2.y = hints->y_delta;
+
+ /* be sure to check for spacing glyphs */
+ if ( slot->outline.n_points == 0 )
+ goto Hint_Metrics;
+
+ /* now load the slot image into the auto-outline and run the */
+ /* automatic hinting process */
+ if ( metrics->clazz->script_hints_apply )
+ metrics->clazz->script_hints_apply( hints,
+ &gloader->current.outline,
+ metrics );
+
+ /* we now need to hint the metrics according to the change in */
+ /* width/positioning that occurred during the hinting process */
+ if ( scaler->render_mode != FT_RENDER_MODE_LIGHT )
+ {
+ FT_Pos old_rsb, old_lsb, new_lsb;
+ FT_Pos pp1x_uh, pp2x_uh;
+ AF_AxisHints axis = &hints->axis[AF_DIMENSION_HORZ];
+ AF_Edge edge1 = axis->edges; /* leftmost edge */
+ AF_Edge edge2 = edge1 +
+ axis->num_edges - 1; /* rightmost edge */
+
+
+ if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) )
+ {
+ old_rsb = loader->pp2.x - edge2->opos;
+ old_lsb = edge1->opos;
+ new_lsb = edge1->pos;
+
+ /* remember unhinted values to later account */
+ /* for rounding errors */
+
+ pp1x_uh = new_lsb - old_lsb;
+ pp2x_uh = edge2->pos + old_rsb;
+
+ /* prefer too much space over too little space */
+ /* for very small sizes */
+
+ if ( old_lsb < 24 )
+ pp1x_uh -= 8;
+
+ if ( old_rsb < 24 )
+ pp2x_uh += 8;
+
+ loader->pp1.x = FT_PIX_ROUND( pp1x_uh );
+ loader->pp2.x = FT_PIX_ROUND( pp2x_uh );
+
+ if ( loader->pp1.x >= new_lsb && old_lsb > 0 )
+ loader->pp1.x -= 64;
+
+ if ( loader->pp2.x <= edge2->pos && old_rsb > 0 )
+ loader->pp2.x += 64;
+
+ slot->lsb_delta = loader->pp1.x - pp1x_uh;
+ slot->rsb_delta = loader->pp2.x - pp2x_uh;
+ }
+ else
+ {
+ FT_Pos pp1x = loader->pp1.x;
+ FT_Pos pp2x = loader->pp2.x;
+
+ loader->pp1.x = FT_PIX_ROUND( pp1x );
+ loader->pp2.x = FT_PIX_ROUND( pp2x );
+
+ slot->lsb_delta = loader->pp1.x - pp1x;
+ slot->rsb_delta = loader->pp2.x - pp2x;
+ }
+ }
+ else
+ {
+ FT_Pos pp1x = loader->pp1.x;
+ FT_Pos pp2x = loader->pp2.x;
+
+ loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta );
+ loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta );
+
+ slot->lsb_delta = loader->pp1.x - pp1x;
+ slot->rsb_delta = loader->pp2.x - pp2x;
+ }
+
+ /* good, we simply add the glyph to our loader's base */
+ FT_GlyphLoader_Add( gloader );
+ break;
+
+ case FT_GLYPH_FORMAT_COMPOSITE:
+ {
+ FT_UInt nn, num_subglyphs = slot->num_subglyphs;
+ FT_UInt num_base_subgs, start_point;
+ FT_SubGlyph subglyph;
+
+
+ start_point = gloader->base.outline.n_points;
+
+ /* first of all, copy the subglyph descriptors in the glyph loader */
+ error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs );
+ if ( error )
+ goto Exit;
+
+ FT_ARRAY_COPY( gloader->current.subglyphs,
+ slot->subglyphs,
+ num_subglyphs );
+
+ gloader->current.num_subglyphs = num_subglyphs;
+ num_base_subgs = gloader->base.num_subglyphs;
+
+ /* now, read each subglyph independently */
+ for ( nn = 0; nn < num_subglyphs; nn++ )
+ {
+ FT_Vector pp1, pp2;
+ FT_Pos x, y;
+ FT_UInt num_points, num_new_points, num_base_points;
+
+
+ /* gloader.current.subglyphs can change during glyph loading due */
+ /* to re-allocation -- we must recompute the current subglyph on */
+ /* each iteration */
+ subglyph = gloader->base.subglyphs + num_base_subgs + nn;
+
+ pp1 = loader->pp1;
+ pp2 = loader->pp2;
+
+ num_base_points = gloader->base.outline.n_points;
+
+ error = af_loader_load_g( loader, scaler, subglyph->index,
+ load_flags, depth + 1 );
+ if ( error )
+ goto Exit;
+
+ /* recompute subglyph pointer */
+ subglyph = gloader->base.subglyphs + num_base_subgs + nn;
+
+ if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS )
+ {
+ pp1 = loader->pp1;
+ pp2 = loader->pp2;
+ }
+ else
+ {
+ loader->pp1 = pp1;
+ loader->pp2 = pp2;
+ }
+
+ num_points = gloader->base.outline.n_points;
+ num_new_points = num_points - num_base_points;
+
+ /* now perform the transform required for this subglyph */
+
+ if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE |
+ FT_SUBGLYPH_FLAG_XY_SCALE |
+ FT_SUBGLYPH_FLAG_2X2 ) )
+ {
+ FT_Vector* cur = gloader->base.outline.points +
+ num_base_points;
+ FT_Vector* limit = cur + num_new_points;
+
+
+ for ( ; cur < limit; cur++ )
+ FT_Vector_Transform( cur, &subglyph->transform );
+ }
+
+ /* apply offset */
+
+ if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) )
+ {
+ FT_Int k = subglyph->arg1;
+ FT_UInt l = subglyph->arg2;
+ FT_Vector* p1;
+ FT_Vector* p2;
+
+
+ if ( start_point + k >= num_base_points ||
+ l >= (FT_UInt)num_new_points )
+ {
+ error = AF_Err_Invalid_Composite;
+ goto Exit;
+ }
+
+ l += num_base_points;
+
+ /* for now, only use the current point coordinates; */
+ /* we may consider another approach in the near future */
+ p1 = gloader->base.outline.points + start_point + k;
+ p2 = gloader->base.outline.points + start_point + l;
+
+ x = p1->x - p2->x;
+ y = p1->y - p2->y;
+ }
+ else
+ {
+ x = FT_MulFix( subglyph->arg1, hints->x_scale ) + hints->x_delta;
+ y = FT_MulFix( subglyph->arg2, hints->y_scale ) + hints->y_delta;
+
+ x = FT_PIX_ROUND( x );
+ y = FT_PIX_ROUND( y );
+ }
+
+ {
+ FT_Outline dummy = gloader->base.outline;
+
+
+ dummy.points += num_base_points;
+ dummy.n_points = (short)num_new_points;
+
+ FT_Outline_Translate( &dummy, x, y );
+ }
+ }
+ }
+ break;
+
+ default:
+ /* we don't support other formats (yet?) */
+ error = AF_Err_Unimplemented_Feature;
+ }
+
+ Hint_Metrics:
+ if ( depth == 0 )
+ {
+ FT_BBox bbox;
+ FT_Vector vvector;
+
+
+ vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX;
+ vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY;
+ vvector.x = FT_MulFix( vvector.x, metrics->scaler.x_scale );
+ vvector.y = FT_MulFix( vvector.y, metrics->scaler.y_scale );
+
+ /* transform the hinted outline if needed */
+ if ( loader->transformed )
+ {
+ FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix );
+ FT_Vector_Transform( &vvector, &loader->trans_matrix );
+ }
+#if 1
+ /* we must translate our final outline by -pp1.x and compute */
+ /* the new metrics */
+ if ( loader->pp1.x )
+ FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 );
+#endif
+ FT_Outline_Get_CBox( &gloader->base.outline, &bbox );
+
+ bbox.xMin = FT_PIX_FLOOR( bbox.xMin );
+ bbox.yMin = FT_PIX_FLOOR( bbox.yMin );
+ bbox.xMax = FT_PIX_CEIL( bbox.xMax );
+ bbox.yMax = FT_PIX_CEIL( bbox.yMax );
+
+ slot->metrics.width = bbox.xMax - bbox.xMin;
+ slot->metrics.height = bbox.yMax - bbox.yMin;
+ slot->metrics.horiBearingX = bbox.xMin;
+ slot->metrics.horiBearingY = bbox.yMax;
+
+ slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x );
+ slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y );
+
+ /* for mono-width fonts (like Andale, Courier, etc.) we need */
+ /* to keep the original rounded advance width */
+#if 0
+ if ( !FT_IS_FIXED_WIDTH( slot->face ) )
+ slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
+ else
+ slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
+ x_scale );
+#else
+ if ( !FT_IS_FIXED_WIDTH( slot->face ) )
+ {
+ /* non-spacing glyphs must stay as-is */
+ if ( slot->metrics.horiAdvance )
+ slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
+ }
+ else
+ {
+ slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
+ metrics->scaler.x_scale );
+
+ /* Set delta values to 0. Otherwise code that uses them is */
+ /* going to ruin the fixed advance width. */
+ slot->lsb_delta = 0;
+ slot->rsb_delta = 0;
+ }
+#endif
+
+ slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance,
+ metrics->scaler.y_scale );
+
+ slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance );
+ slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance );
+
+ /* now copy outline into glyph slot */
+ FT_GlyphLoader_Rewind( internal->loader );
+ error = FT_GlyphLoader_CopyPoints( internal->loader, gloader );
+ if ( error )
+ goto Exit;
+
+ slot->outline = internal->loader->base.outline;
+ slot->format = FT_GLYPH_FORMAT_OUTLINE;
+ }
+
+#ifdef DEBUG_HINTER
+ af_debug_hinter = hinter;
+#endif
+
+ Exit:
+ return error;
+ }
+
+
+ FT_LOCAL_DEF( FT_Error )
+ af_loader_load_glyph( AF_Loader loader,
+ FT_Face face,
+ FT_UInt gindex,
+ FT_UInt32 load_flags )
+ {
+ FT_Error error;
+ FT_Size size = face->size;
+ AF_ScalerRec scaler;
+
+
+ if ( !size )
+ return AF_Err_Invalid_Argument;
+
+ FT_ZERO( &scaler );
+
+ scaler.face = face;
+ scaler.x_scale = size->metrics.x_scale;
+ scaler.x_delta = 0; /* XXX: TODO: add support for sub-pixel hinting */
+ scaler.y_scale = size->metrics.y_scale;
+ scaler.y_delta = 0; /* XXX: TODO: add support for sub-pixel hinting */
+
+ scaler.render_mode = FT_LOAD_TARGET_MODE( load_flags );
+ scaler.flags = 0; /* XXX: fix this */
+
+ error = af_loader_reset( loader, face );
+ if ( !error )
+ {
+ AF_ScriptMetrics metrics;
+ FT_UInt options = 0;
+
+
+#ifdef FT_OPTION_AUTOFIT2
+ /* XXX: undocumented hook to activate the latin2 hinter */
+ if ( load_flags & ( 1UL << 20 ) )
+ options = 2;
+#endif
+
+ error = af_face_globals_get_metrics( loader->globals, gindex,
+ options, &metrics );
+ if ( !error )
+ {
+ loader->metrics = metrics;
+
+ if ( metrics->clazz->script_metrics_scale )
+ metrics->clazz->script_metrics_scale( metrics, &scaler );
+ else
+ metrics->scaler = scaler;
+
+ load_flags |= FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM;
+ load_flags &= ~FT_LOAD_RENDER;
+
+ if ( metrics->clazz->script_hints_init )
+ {
+ error = metrics->clazz->script_hints_init( &loader->hints,
+ metrics );
+ if ( error )
+ goto Exit;
+ }
+
+ error = af_loader_load_g( loader, &scaler, gindex, load_flags, 0 );
+ }
+ }
+ Exit:
+ return error;
+ }
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/afloader.h b/src/3rdparty/freetype/src/autofit/afloader.h
new file mode 100644
index 0000000000..fa67c10ffe
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/afloader.h
@@ -0,0 +1,73 @@
+/***************************************************************************/
+/* */
+/* afloader.h */
+/* */
+/* Auto-fitter glyph loading routines (specification). */
+/* */
+/* Copyright 2003, 2004, 2005 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AF_LOADER_H__
+#define __AF_LOADER_H__
+
+#include "afhints.h"
+#include "afglobal.h"
+
+
+FT_BEGIN_HEADER
+
+ typedef struct AF_LoaderRec_
+ {
+ FT_Face face; /* current face */
+ AF_FaceGlobals globals; /* current face globals */
+ FT_GlyphLoader gloader; /* glyph loader */
+ AF_GlyphHintsRec hints;
+ AF_ScriptMetrics metrics;
+ FT_Bool transformed;
+ FT_Matrix trans_matrix;
+ FT_Vector trans_delta;
+ FT_Vector pp1;
+ FT_Vector pp2;
+ /* we don't handle vertical phantom points */
+
+ } AF_LoaderRec, *AF_Loader;
+
+
+ FT_LOCAL( FT_Error )
+ af_loader_init( AF_Loader loader,
+ FT_Memory memory );
+
+
+ FT_LOCAL( FT_Error )
+ af_loader_reset( AF_Loader loader,
+ FT_Face face );
+
+
+ FT_LOCAL( void )
+ af_loader_done( AF_Loader loader );
+
+
+ FT_LOCAL( FT_Error )
+ af_loader_load_glyph( AF_Loader loader,
+ FT_Face face,
+ FT_UInt gindex,
+ FT_UInt32 load_flags );
+
+/* */
+
+
+FT_END_HEADER
+
+#endif /* __AF_LOADER_H__ */
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/afmodule.c b/src/3rdparty/freetype/src/autofit/afmodule.c
new file mode 100644
index 0000000000..cd5e1cc218
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/afmodule.c
@@ -0,0 +1,97 @@
+/***************************************************************************/
+/* */
+/* afmodule.c */
+/* */
+/* Auto-fitter module implementation (body). */
+/* */
+/* Copyright 2003, 2004, 2005, 2006 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "afmodule.h"
+#include "afloader.h"
+
+#ifdef AF_DEBUG
+ int _af_debug;
+ int _af_debug_disable_horz_hints;
+ int _af_debug_disable_vert_hints;
+ int _af_debug_disable_blue_hints;
+ void* _af_debug_hints;
+#endif
+
+#include FT_INTERNAL_OBJECTS_H
+
+
+ typedef struct FT_AutofitterRec_
+ {
+ FT_ModuleRec root;
+ AF_LoaderRec loader[1];
+
+ } FT_AutofitterRec, *FT_Autofitter;
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ af_autofitter_init( FT_Autofitter module )
+ {
+ return af_loader_init( module->loader, module->root.library->memory );
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ af_autofitter_done( FT_Autofitter module )
+ {
+ af_loader_done( module->loader );
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ af_autofitter_load_glyph( FT_Autofitter module,
+ FT_GlyphSlot slot,
+ FT_Size size,
+ FT_UInt glyph_index,
+ FT_Int32 load_flags )
+ {
+ FT_UNUSED( size );
+
+ return af_loader_load_glyph( module->loader, slot->face,
+ glyph_index, load_flags );
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_AutoHinter_ServiceRec af_autofitter_service =
+ {
+ NULL,
+ NULL,
+ NULL,
+ (FT_AutoHinter_GlyphLoadFunc)af_autofitter_load_glyph
+ };
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Module_Class autofit_module_class =
+ {
+ FT_MODULE_HINTER,
+ sizeof ( FT_AutofitterRec ),
+
+ "autofitter",
+ 0x10000L, /* version 1.0 of the autofitter */
+ 0x20000L, /* requires FreeType 2.0 or above */
+
+ (const void*)&af_autofitter_service,
+
+ (FT_Module_Constructor)af_autofitter_init,
+ (FT_Module_Destructor) af_autofitter_done,
+ (FT_Module_Requester) NULL
+ };
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/afmodule.h b/src/3rdparty/freetype/src/autofit/afmodule.h
new file mode 100644
index 0000000000..36268a0890
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/afmodule.h
@@ -0,0 +1,37 @@
+/***************************************************************************/
+/* */
+/* afmodule.h */
+/* */
+/* Auto-fitter module implementation (specification). */
+/* */
+/* Copyright 2003, 2004, 2005 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AFMODULE_H__
+#define __AFMODULE_H__
+
+#include <ft2build.h>
+#include FT_MODULE_H
+
+
+FT_BEGIN_HEADER
+
+ FT_CALLBACK_TABLE
+ const FT_Module_Class autofit_module_class;
+
+
+FT_END_HEADER
+
+#endif /* __AFMODULE_H__ */
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/aftypes.h b/src/3rdparty/freetype/src/autofit/aftypes.h
new file mode 100644
index 0000000000..626a38865e
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/aftypes.h
@@ -0,0 +1,350 @@
+/***************************************************************************/
+/* */
+/* aftypes.h */
+/* */
+/* Auto-fitter types (specification only). */
+/* */
+/* Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************
+ *
+ * The auto-fitter is a complete rewrite of the old auto-hinter.
+ * Its main feature is the ability to differentiate between different
+ * scripts in order to apply language-specific rules.
+ *
+ * The code has also been compartmentized into several entities that
+ * should make algorithmic experimentation easier than with the old
+ * code.
+ *
+ * Finally, we get rid of the Catharon license, since this code is
+ * released under the FreeType one.
+ *
+ *************************************************************************/
+
+
+#ifndef __AFTYPES_H__
+#define __AFTYPES_H__
+
+#include <ft2build.h>
+
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+
+
+FT_BEGIN_HEADER
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** D E B U G G I N G *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+#define xxAF_USE_WARPER /* only define to use warp hinting */
+#define xxAF_DEBUG
+
+#ifdef AF_DEBUG
+
+#include FT_CONFIG_STANDARD_LIBRARY_H
+
+#define AF_LOG( x ) do { if ( _af_debug ) printf x; } while ( 0 )
+
+extern int _af_debug;
+extern int _af_debug_disable_horz_hints;
+extern int _af_debug_disable_vert_hints;
+extern int _af_debug_disable_blue_hints;
+extern void* _af_debug_hints;
+
+#else /* !AF_DEBUG */
+
+#define AF_LOG( x ) do { } while ( 0 ) /* nothing */
+
+#endif /* !AF_DEBUG */
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** U T I L I T Y S T U F F *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ typedef struct AF_WidthRec_
+ {
+ FT_Pos org; /* original position/width in font units */
+ FT_Pos cur; /* current/scaled position/width in device sub-pixels */
+ FT_Pos fit; /* current/fitted position/width in device sub-pixels */
+
+ } AF_WidthRec, *AF_Width;
+
+
+ FT_LOCAL( void )
+ af_sort_pos( FT_UInt count,
+ FT_Pos* table );
+
+ FT_LOCAL( void )
+ af_sort_widths( FT_UInt count,
+ AF_Width widths );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** A N G L E T Y P E S *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*
+ * The auto-fitter doesn't need a very high angular accuracy;
+ * this allows us to speed up some computations considerably with a
+ * light Cordic algorithm (see afangles.c).
+ */
+
+ typedef FT_Int AF_Angle;
+
+
+#define AF_ANGLE_PI 256
+#define AF_ANGLE_2PI ( AF_ANGLE_PI * 2 )
+#define AF_ANGLE_PI2 ( AF_ANGLE_PI / 2 )
+#define AF_ANGLE_PI4 ( AF_ANGLE_PI / 4 )
+
+
+#if 0
+ /*
+ * compute the angle of a given 2-D vector
+ */
+ FT_LOCAL( AF_Angle )
+ af_angle_atan( FT_Pos dx,
+ FT_Pos dy );
+
+
+ /*
+ * compute `angle2 - angle1'; the result is always within
+ * the range [-AF_ANGLE_PI .. AF_ANGLE_PI - 1]
+ */
+ FT_LOCAL( AF_Angle )
+ af_angle_diff( AF_Angle angle1,
+ AF_Angle angle2 );
+#endif /* 0 */
+
+
+#define AF_ANGLE_DIFF( result, angle1, angle2 ) \
+ FT_BEGIN_STMNT \
+ AF_Angle _delta = (angle2) - (angle1); \
+ \
+ \
+ _delta %= AF_ANGLE_2PI; \
+ if ( _delta < 0 ) \
+ _delta += AF_ANGLE_2PI; \
+ \
+ if ( _delta > AF_ANGLE_PI ) \
+ _delta -= AF_ANGLE_2PI; \
+ \
+ result = _delta; \
+ FT_END_STMNT
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** O U T L I N E S *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* opaque handle to glyph-specific hints -- see `afhints.h' for more
+ * details
+ */
+ typedef struct AF_GlyphHintsRec_* AF_GlyphHints;
+
+ /* This structure is used to model an input glyph outline to
+ * the auto-hinter. The latter will set the `hints' field
+ * depending on the glyph's script.
+ */
+ typedef struct AF_OutlineRec_
+ {
+ FT_Face face;
+ FT_Outline outline;
+ FT_UInt outline_resolution;
+
+ FT_Int advance;
+ FT_UInt metrics_resolution;
+
+ AF_GlyphHints hints;
+
+ } AF_OutlineRec;
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** S C A L E R S *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*
+ * A scaler models the target pixel device that will receive the
+ * auto-hinted glyph image.
+ */
+
+ typedef enum AF_ScalerFlags_
+ {
+ AF_SCALER_FLAG_NO_HORIZONTAL = 1, /* disable horizontal hinting */
+ AF_SCALER_FLAG_NO_VERTICAL = 2, /* disable vertical hinting */
+ AF_SCALER_FLAG_NO_ADVANCE = 4 /* disable advance hinting */
+
+ } AF_ScalerFlags;
+
+
+ typedef struct AF_ScalerRec_
+ {
+ FT_Face face; /* source font face */
+ FT_Fixed x_scale; /* from font units to 1/64th device pixels */
+ FT_Fixed y_scale; /* from font units to 1/64th device pixels */
+ FT_Pos x_delta; /* in 1/64th device pixels */
+ FT_Pos y_delta; /* in 1/64th device pixels */
+ FT_Render_Mode render_mode; /* monochrome, anti-aliased, LCD, etc. */
+ FT_UInt32 flags; /* additional control flags, see above */
+
+ } AF_ScalerRec, *AF_Scaler;
+
+
+#define AF_SCALER_EQUAL_SCALES( a, b ) \
+ ( (a)->x_scale == (b)->x_scale && \
+ (a)->y_scale == (b)->y_scale && \
+ (a)->x_delta == (b)->x_delta && \
+ (a)->y_delta == (b)->y_delta )
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** S C R I P T S *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*
+ * The list of know scripts. Each different script corresponds to the
+ * following information:
+ *
+ * - A set of Unicode ranges to test whether the face supports the
+ * script.
+ *
+ * - A specific global analyzer that will compute global metrics
+ * specific to the script.
+ *
+ * - A specific glyph analyzer that will compute segments and
+ * edges for each glyph covered by the script.
+ *
+ * - A specific grid-fitting algorithm that will distort the
+ * scaled glyph outline according to the results of the glyph
+ * analyzer.
+ *
+ * Note that a given analyzer and/or grid-fitting algorithm can be
+ * used by more than one script.
+ */
+
+ typedef enum AF_Script_
+ {
+ AF_SCRIPT_NONE = 0,
+ AF_SCRIPT_LATIN = 1,
+ AF_SCRIPT_CJK = 2,
+ AF_SCRIPT_INDIC = 3,
+#ifdef FT_OPTION_AUTOFIT2
+ AF_SCRIPT_LATIN2,
+#endif
+
+ /* add new scripts here. Don't forget to update the list in */
+ /* `afglobal.c'. */
+
+ AF_SCRIPT_MAX /* do not remove */
+
+ } AF_Script;
+
+
+ typedef struct AF_ScriptClassRec_ const* AF_ScriptClass;
+
+ typedef struct AF_ScriptMetricsRec_
+ {
+ AF_ScriptClass clazz;
+ AF_ScalerRec scaler;
+
+ } AF_ScriptMetricsRec, *AF_ScriptMetrics;
+
+
+ /* This function parses an FT_Face to compute global metrics for
+ * a specific script.
+ */
+ typedef FT_Error
+ (*AF_Script_InitMetricsFunc)( AF_ScriptMetrics metrics,
+ FT_Face face );
+
+ typedef void
+ (*AF_Script_ScaleMetricsFunc)( AF_ScriptMetrics metrics,
+ AF_Scaler scaler );
+
+ typedef void
+ (*AF_Script_DoneMetricsFunc)( AF_ScriptMetrics metrics );
+
+
+ typedef FT_Error
+ (*AF_Script_InitHintsFunc)( AF_GlyphHints hints,
+ AF_ScriptMetrics metrics );
+
+ typedef void
+ (*AF_Script_ApplyHintsFunc)( AF_GlyphHints hints,
+ FT_Outline* outline,
+ AF_ScriptMetrics metrics );
+
+
+ typedef struct AF_Script_UniRangeRec_
+ {
+ FT_UInt32 first;
+ FT_UInt32 last;
+
+ } AF_Script_UniRangeRec;
+
+ typedef const AF_Script_UniRangeRec *AF_Script_UniRange;
+
+
+ typedef struct AF_ScriptClassRec_
+ {
+ AF_Script script;
+ AF_Script_UniRange script_uni_ranges; /* last must be { 0, 0 } */
+
+ FT_UInt script_metrics_size;
+ AF_Script_InitMetricsFunc script_metrics_init;
+ AF_Script_ScaleMetricsFunc script_metrics_scale;
+ AF_Script_DoneMetricsFunc script_metrics_done;
+
+ AF_Script_InitHintsFunc script_hints_init;
+ AF_Script_ApplyHintsFunc script_hints_apply;
+
+ } AF_ScriptClassRec;
+
+
+/* */
+
+FT_END_HEADER
+
+#endif /* __AFTYPES_H__ */
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/afwarp.c b/src/3rdparty/freetype/src/autofit/afwarp.c
new file mode 100644
index 0000000000..f5bb9b18ad
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/afwarp.c
@@ -0,0 +1,338 @@
+/***************************************************************************/
+/* */
+/* afwarp.c */
+/* */
+/* Auto-fitter warping algorithm (body). */
+/* */
+/* Copyright 2006, 2007 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include "afwarp.h"
+
+#ifdef AF_USE_WARPER
+
+#if 1
+ static const AF_WarpScore
+ af_warper_weights[64] =
+ {
+ 35, 32, 30, 25, 20, 15, 12, 10, 5, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -1, -2, -5, -8,-10,-10,-20,-20,-30,-30,
+
+ -30,-30,-20,-20,-10,-10, -8, -5, -2, -1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 5, 10, 12, 15, 20, 25, 30, 32,
+ };
+#else
+ static const AF_WarpScore
+ af_warper_weights[64] =
+ {
+ 30, 20, 10, 5, 4, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, -1, -2, -2, -5, -5,-10,-10,-15,-20,
+
+ -20,-15,-15,-10,-10, -5, -5, -2, -2, -1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 4, 5, 10, 20,
+ };
+#endif
+
+
+ static void
+ af_warper_compute_line_best( AF_Warper warper,
+ FT_Fixed scale,
+ FT_Pos delta,
+ FT_Pos xx1,
+ FT_Pos xx2,
+ AF_WarpScore base_distort,
+ AF_Segment segments,
+ FT_UInt num_segments )
+ {
+ FT_Int idx_min, idx_max, idx0;
+ FT_UInt nn;
+ AF_WarpScore scores[65];
+
+
+ for ( nn = 0; nn < 65; nn++ )
+ scores[nn] = 0;
+
+ idx0 = xx1 - warper->t1;
+
+ /* compute minimum and maximum indices */
+ {
+ FT_Pos xx1min = warper->x1min;
+ FT_Pos xx1max = warper->x1max;
+ FT_Pos w = xx2 - xx1;
+
+
+ if ( xx1min + w < warper->x2min )
+ xx1min = warper->x2min - w;
+
+ xx1max = warper->x1max;
+ if ( xx1max + w > warper->x2max )
+ xx1max = warper->x2max - w;
+
+ idx_min = xx1min - warper->t1;
+ idx_max = xx1max - warper->t1;
+
+ if ( idx_min < 0 || idx_min > idx_max || idx_max > 64 )
+ {
+ AF_LOG(( "invalid indices:\n"
+ " min=%d max=%d, xx1=%ld xx2=%ld,\n"
+ " x1min=%ld x1max=%ld, x2min=%ld x2max=%ld\n",
+ idx_min, idx_max, xx1, xx2,
+ warper->x1min, warper->x1max,
+ warper->x2min, warper->x2max ));
+ return;
+ }
+ }
+
+ for ( nn = 0; nn < num_segments; nn++ )
+ {
+ FT_Pos len = segments[nn].max_coord - segments[nn].min_coord;
+ FT_Pos y0 = FT_MulFix( segments[nn].pos, scale ) + delta;
+ FT_Pos y = y0 + ( idx_min - idx0 );
+ FT_Int idx;
+
+
+ for ( idx = idx_min; idx <= idx_max; idx++, y++ )
+ scores[idx] += af_warper_weights[y & 63] * len;
+ }
+
+ /* find best score */
+ {
+ FT_Int idx;
+
+
+ for ( idx = idx_min; idx <= idx_max; idx++ )
+ {
+ AF_WarpScore score = scores[idx];
+ AF_WarpScore distort = base_distort + ( idx - idx0 );
+
+
+ if ( score > warper->best_score ||
+ ( score == warper->best_score &&
+ distort < warper->best_distort ) )
+ {
+ warper->best_score = score;
+ warper->best_distort = distort;
+ warper->best_scale = scale;
+ warper->best_delta = delta + ( idx - idx0 );
+ }
+ }
+ }
+ }
+
+
+ FT_LOCAL_DEF( void )
+ af_warper_compute( AF_Warper warper,
+ AF_GlyphHints hints,
+ AF_Dimension dim,
+ FT_Fixed *a_scale,
+ FT_Pos *a_delta )
+ {
+ AF_AxisHints axis;
+ AF_Point points;
+
+ FT_Fixed org_scale;
+ FT_Pos org_delta;
+
+ FT_UInt nn, num_points, num_segments;
+ FT_Int X1, X2;
+ FT_Int w;
+
+ AF_WarpScore base_distort;
+ AF_Segment segments;
+
+
+ /* get original scaling transformation */
+ if ( dim == AF_DIMENSION_VERT )
+ {
+ org_scale = hints->y_scale;
+ org_delta = hints->y_delta;
+ }
+ else
+ {
+ org_scale = hints->x_scale;
+ org_delta = hints->x_delta;
+ }
+
+ warper->best_scale = org_scale;
+ warper->best_delta = org_delta;
+ warper->best_score = INT_MIN;
+ warper->best_distort = 0;
+
+ axis = &hints->axis[dim];
+ segments = axis->segments;
+ num_segments = axis->num_segments;
+ points = hints->points;
+ num_points = hints->num_points;
+
+ *a_scale = org_scale;
+ *a_delta = org_delta;
+
+ /* get X1 and X2, minimum and maximum in original coordinates */
+ if ( num_segments < 1 )
+ return;
+
+#if 1
+ X1 = X2 = points[0].fx;
+ for ( nn = 1; nn < num_points; nn++ )
+ {
+ FT_Int X = points[nn].fx;
+
+
+ if ( X < X1 )
+ X1 = X;
+ if ( X > X2 )
+ X2 = X;
+ }
+#else
+ X1 = X2 = segments[0].pos;
+ for ( nn = 1; nn < num_segments; nn++ )
+ {
+ FT_Int X = segments[nn].pos;
+
+
+ if ( X < X1 )
+ X1 = X;
+ if ( X > X2 )
+ X2 = X;
+ }
+#endif
+
+ if ( X1 >= X2 )
+ return;
+
+ warper->x1 = FT_MulFix( X1, org_scale ) + org_delta;
+ warper->x2 = FT_MulFix( X2, org_scale ) + org_delta;
+
+ warper->t1 = AF_WARPER_FLOOR( warper->x1 );
+ warper->t2 = AF_WARPER_CEIL( warper->x2 );
+
+ warper->x1min = warper->x1 & ~31;
+ warper->x1max = warper->x1min + 32;
+ warper->x2min = warper->x2 & ~31;
+ warper->x2max = warper->x2min + 32;
+
+ if ( warper->x1max > warper->x2 )
+ warper->x1max = warper->x2;
+
+ if ( warper->x2min < warper->x1 )
+ warper->x2min = warper->x1;
+
+ warper->w0 = warper->x2 - warper->x1;
+
+ if ( warper->w0 <= 64 )
+ {
+ warper->x1max = warper->x1;
+ warper->x2min = warper->x2;
+ }
+
+ warper->wmin = warper->x2min - warper->x1max;
+ warper->wmax = warper->x2max - warper->x1min;
+
+#if 1
+ {
+ int margin = 16;
+
+
+ if ( warper->w0 <= 128 )
+ {
+ margin = 8;
+ if ( warper->w0 <= 96 )
+ margin = 4;
+ }
+
+ if ( warper->wmin < warper->w0 - margin )
+ warper->wmin = warper->w0 - margin;
+
+ if ( warper->wmax > warper->w0 + margin )
+ warper->wmax = warper->w0 + margin;
+ }
+
+ if ( warper->wmin < warper->w0 * 3 / 4 )
+ warper->wmin = warper->w0 * 3 / 4;
+
+ if ( warper->wmax > warper->w0 * 5 / 4 )
+ warper->wmax = warper->w0 * 5 / 4;
+#else
+ /* no scaling, just translation */
+ warper->wmin = warper->wmax = warper->w0;
+#endif
+
+ for ( w = warper->wmin; w <= warper->wmax; w++ )
+ {
+ FT_Fixed new_scale;
+ FT_Pos new_delta;
+ FT_Pos xx1, xx2;
+
+
+ xx1 = warper->x1;
+ xx2 = warper->x2;
+ if ( w >= warper->w0 )
+ {
+ xx1 -= w - warper->w0;
+ if ( xx1 < warper->x1min )
+ {
+ xx2 += warper->x1min - xx1;
+ xx1 = warper->x1min;
+ }
+ }
+ else
+ {
+ xx1 -= w - warper->w0;
+ if ( xx1 > warper->x1max )
+ {
+ xx2 -= xx1 - warper->x1max;
+ xx1 = warper->x1max;
+ }
+ }
+
+ if ( xx1 < warper->x1 )
+ base_distort = warper->x1 - xx1;
+ else
+ base_distort = xx1 - warper->x1;
+
+ if ( xx2 < warper->x2 )
+ base_distort += warper->x2 - xx2;
+ else
+ base_distort += xx2 - warper->x2;
+
+ base_distort *= 10;
+
+ new_scale = org_scale + FT_DivFix( w - warper->w0, X2 - X1 );
+ new_delta = xx1 - FT_MulFix( X1, new_scale );
+
+ af_warper_compute_line_best( warper, new_scale, new_delta, xx1, xx2,
+ base_distort,
+ segments, num_segments );
+ }
+
+ {
+ FT_Fixed best_scale = warper->best_scale;
+ FT_Pos best_delta = warper->best_delta;
+
+
+ hints->xmin_delta = FT_MulFix( X1, best_scale - org_scale )
+ + best_delta;
+ hints->xmax_delta = FT_MulFix( X2, best_scale - org_scale )
+ + best_delta;
+
+ *a_scale = best_scale;
+ *a_delta = best_delta;
+ }
+ }
+
+#else /* !AF_USE_WARPER */
+
+char af_warper_dummy = 0; /* make compiler happy */
+
+#endif /* !AF_USE_WARPER */
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/afwarp.h b/src/3rdparty/freetype/src/autofit/afwarp.h
new file mode 100644
index 0000000000..7343fdd5ef
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/afwarp.h
@@ -0,0 +1,64 @@
+/***************************************************************************/
+/* */
+/* afwarp.h */
+/* */
+/* Auto-fitter warping algorithm (specification). */
+/* */
+/* Copyright 2006, 2007 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __AFWARP_H__
+#define __AFWARP_H__
+
+#include "afhints.h"
+
+FT_BEGIN_HEADER
+
+#define AF_WARPER_SCALE
+
+#define AF_WARPER_FLOOR( x ) ( (x) & ~63 )
+#define AF_WARPER_CEIL( x ) AF_WARPER_FLOOR( (x) + 63 )
+
+
+ typedef FT_Int32 AF_WarpScore;
+
+ typedef struct AF_WarperRec_
+ {
+ FT_Pos x1, x2;
+ FT_Pos t1, t2;
+ FT_Pos x1min, x1max;
+ FT_Pos x2min, x2max;
+ FT_Pos w0, wmin, wmax;
+
+ FT_Fixed best_scale;
+ FT_Pos best_delta;
+ AF_WarpScore best_score;
+ AF_WarpScore best_distort;
+
+ } AF_WarperRec, *AF_Warper;
+
+
+ FT_LOCAL( void )
+ af_warper_compute( AF_Warper warper,
+ AF_GlyphHints hints,
+ AF_Dimension dim,
+ FT_Fixed *a_scale,
+ FT_Fixed *a_delta );
+
+
+FT_END_HEADER
+
+
+#endif /* __AFWARP_H__ */
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/autofit.c b/src/3rdparty/freetype/src/autofit/autofit.c
new file mode 100644
index 0000000000..2fe66a990e
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/autofit.c
@@ -0,0 +1,40 @@
+/***************************************************************************/
+/* */
+/* autofit.c */
+/* */
+/* Auto-fitter module (body). */
+/* */
+/* Copyright 2003, 2004, 2005, 2006, 2007 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+#include <ft2build.h>
+#include "afangles.c"
+#include "afglobal.c"
+#include "afhints.c"
+
+#include "afdummy.c"
+#include "aflatin.c"
+#ifdef FT_OPTION_AUTOFIT2
+#include "aflatin2.c"
+#endif
+#include "afcjk.c"
+#include "afindic.c"
+
+#include "afloader.c"
+#include "afmodule.c"
+
+#ifdef AF_USE_WARPER
+#include "afwarp.c"
+#endif
+
+/* END */
diff --git a/src/3rdparty/freetype/src/autofit/module.mk b/src/3rdparty/freetype/src/autofit/module.mk
new file mode 100644
index 0000000000..6ec60912ab
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/module.mk
@@ -0,0 +1,23 @@
+#
+# FreeType 2 auto-fitter module definition
+#
+
+
+# Copyright 2003, 2004, 2005, 2006 by
+# David Turner, Robert Wilhelm, and Werner Lemberg.
+#
+# This file is part of the FreeType project, and may only be used, modified,
+# and distributed under the terms of the FreeType project license,
+# LICENSE.TXT. By continuing to use, modify, or distribute this file you
+# indicate that you have read the license and understand and accept it
+# fully.
+
+
+FTMODULE_H_COMMANDS += AUTOFIT_MODULE
+
+define AUTOFIT_MODULE
+$(OPEN_DRIVER) FT_Module_Class, autofit_module_class $(CLOSE_DRIVER)
+$(ECHO_DRIVER)autofit $(ECHO_DRIVER_DESC)automatic hinting module$(ECHO_DRIVER_DONE)
+endef
+
+# EOF
diff --git a/src/3rdparty/freetype/src/autofit/rules.mk b/src/3rdparty/freetype/src/autofit/rules.mk
new file mode 100644
index 0000000000..017489d9e0
--- /dev/null
+++ b/src/3rdparty/freetype/src/autofit/rules.mk
@@ -0,0 +1,78 @@
+#
+# FreeType 2 auto-fitter module configuration rules
+#
+
+
+# Copyright 2003, 2004, 2005, 2006, 2007 by
+# David Turner, Robert Wilhelm, and Werner Lemberg.
+#
+# This file is part of the FreeType project, and may only be used, modified,
+# and distributed under the terms of the FreeType project license,
+# LICENSE.TXT. By continuing to use, modify, or distribute this file you
+# indicate that you have read the license and understand and accept it
+# fully.
+
+
+# AUTOF driver directory
+#
+AUTOF_DIR := $(SRC_DIR)/autofit
+
+
+# compilation flags for the driver
+#
+AUTOF_COMPILE := $(FT_COMPILE) $I$(subst /,$(COMPILER_SEP),$(AUTOF_DIR))
+
+
+# AUTOF driver sources (i.e., C files)
+#
+AUTOF_DRV_SRC := $(AUTOF_DIR)/afangles.c \
+ $(AUTOF_DIR)/afcjk.c \
+ $(AUTOF_DIR)/afdummy.c \
+ $(AUTOF_DIR)/afglobal.c \
+ $(AUTOF_DIR)/afhints.c \
+ $(AUTOF_DIR)/afindic.c \
+ $(AUTOF_DIR)/aflatin.c \
+ $(AUTOF_DIR)/afloader.c \
+ $(AUTOF_DIR)/afmodule.c \
+ $(AUTOF_DIR)/afwarp.c
+
+# AUTOF driver headers
+#
+AUTOF_DRV_H := $(AUTOF_DRV_SRC:%c=%h) \
+ $(AUTOF_DIR)/aftypes.h \
+ $(AUTOF_DIR)/aferrors.h
+
+
+# AUTOF driver object(s)
+#
+# AUTOF_DRV_OBJ_M is used during `multi' builds.
+# AUTOF_DRV_OBJ_S is used during `single' builds.
+#
+AUTOF_DRV_OBJ_M := $(AUTOF_DRV_SRC:$(AUTOF_DIR)/%.c=$(OBJ_DIR)/%.$O)
+AUTOF_DRV_OBJ_S := $(OBJ_DIR)/autofit.$O
+
+# AUTOF driver source file for single build
+#
+AUTOF_DRV_SRC_S := $(AUTOF_DIR)/autofit.c
+
+
+# AUTOF driver - single object
+#
+$(AUTOF_DRV_OBJ_S): $(AUTOF_DRV_SRC_S) $(AUTOF_DRV_SRC) \
+ $(FREETYPE_H) $(AUTOF_DRV_H)
+ $(AUTOF_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(AUTOF_DRV_SRC_S))
+
+
+# AUTOF driver - multiple objects
+#
+$(OBJ_DIR)/%.$O: $(AUTOF_DIR)/%.c $(FREETYPE_H) $(AUTOF_DRV_H)
+ $(AUTOF_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<)
+
+
+# update main driver object lists
+#
+DRV_OBJS_S += $(AUTOF_DRV_OBJ_S)
+DRV_OBJS_M += $(AUTOF_DRV_OBJ_M)
+
+
+# EOF
diff --git a/src/3rdparty/freetype/src/base/Jamfile b/src/3rdparty/freetype/src/base/Jamfile
new file mode 100644
index 0000000000..aba60fbe0c
--- /dev/null
+++ b/src/3rdparty/freetype/src/base/Jamfile
@@ -0,0 +1,59 @@
+# FreeType 2 src/base Jamfile
+#
+# Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by
+# David Turner, Robert Wilhelm, and Werner Lemberg.
+#
+# This file is part of the FreeType project, and may only be used, modified,
+# and distributed under the terms of the FreeType project license,
+# LICENSE.TXT. By continuing to use, modify, or distribute this file you
+# indicate that you have read the license and understand and accept it
+# fully.
+
+SubDir FT2_TOP $(FT2_SRC_DIR) base ;
+
+
+{
+ local _sources ;
+
+ if $(FT2_MULTI)
+ {
+ _sources = ftadvanc ftcalc ftdbgmem ftgloadr
+ ftnames ftobjs ftoutln ftrfork
+ ftstream fttrigon ftutil
+ ;
+ }
+ else
+ {
+ _sources = ftbase ;
+ }
+
+ Library $(FT2_LIB) : $(_sources).c ;
+}
+
+# Add the optional/replaceable files.
+#
+{
+ local _sources = bbox bdf bitmap debug gasp
+ glyph gxval init lcdfil mm
+ otval pfr stroke synth system
+ type1 winfnt xf86 patent
+ ;
+
+ Library $(FT2_LIB) : ft$(_sources).c ;
+}
+
+# Add Macintosh-specific file to the library when necessary.
+#
+if $(MAC)
+{
+ Library $(FT2_LIB) : ftmac.c ;
+}
+else if $(OS) = MACOSX
+{
+ if $(FT2_MULTI)
+ {
+ Library $(FT2_LIB) : ftmac.c ;
+ }
+}
+
+# end of src/base Jamfile
diff --git a/src/3rdparty/freetype/src/base/ftadvanc.c b/src/3rdparty/freetype/src/base/ftadvanc.c
new file mode 100644
index 0000000000..504f9d2309
--- /dev/null
+++ b/src/3rdparty/freetype/src/base/ftadvanc.c
@@ -0,0 +1,163 @@
+/***************************************************************************/
+/* */
+/* ftadvanc.c */
+/* */
+/* Quick computation of advance widths (body). */
+/* */
+/* Copyright 2008, 2009 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_ADVANCES_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+ static FT_Error
+ _ft_face_scale_advances( FT_Face face,
+ FT_Fixed* advances,
+ FT_UInt count,
+ FT_Int32 flags )
+ {
+ FT_Fixed scale;
+ FT_UInt nn;
+
+
+ if ( flags & FT_LOAD_NO_SCALE )
+ return FT_Err_Ok;
+
+ if ( face->size == NULL )
+ return FT_Err_Invalid_Size_Handle;
+
+ if ( flags & FT_LOAD_VERTICAL_LAYOUT )
+ scale = face->size->metrics.y_scale;
+ else
+ scale = face->size->metrics.x_scale;
+
+ /* this must be the same scaling as to get linear{Hori,Vert}Advance */
+ /* (see `FT_Load_Glyph' implementation in src/base/ftobjs.c) */
+
+ for ( nn = 0; nn < count; nn++ )
+ advances[nn] = FT_MulDiv( advances[nn], scale, 64 );
+
+ return FT_Err_Ok;
+ }
+
+
+ /* at the moment, we can perform fast advance retrieval only in */
+ /* the following cases: */
+ /* */
+ /* - unscaled load */
+ /* - unhinted load */
+ /* - light-hinted load */
+
+#define LOAD_ADVANCE_FAST_CHECK( flags ) \
+ ( flags & ( FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING ) || \
+ FT_LOAD_TARGET_MODE( flags ) == FT_RENDER_MODE_LIGHT )
+
+
+ /* documentation is in ftadvanc.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_Advance( FT_Face face,
+ FT_UInt gindex,
+ FT_Int32 flags,
+ FT_Fixed *padvance )
+ {
+ FT_Face_GetAdvancesFunc func;
+
+
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ if ( gindex >= (FT_UInt)face->num_glyphs )
+ return FT_Err_Invalid_Glyph_Index;
+
+ func = face->driver->clazz->get_advances;
+ if ( func && LOAD_ADVANCE_FAST_CHECK( flags ) )
+ {
+ FT_Error error;
+
+
+ error = func( face, gindex, 1, flags, padvance );
+ if ( !error )
+ return _ft_face_scale_advances( face, padvance, 1, flags );
+
+ if ( error != FT_ERROR_BASE( FT_Err_Unimplemented_Feature ) )
+ return error;
+ }
+
+ return FT_Get_Advances( face, gindex, 1, flags, padvance );
+ }
+
+
+ /* documentation is in ftadvanc.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_Advances( FT_Face face,
+ FT_UInt start,
+ FT_UInt count,
+ FT_Int32 flags,
+ FT_Fixed *padvances )
+ {
+ FT_Face_GetAdvancesFunc func;
+ FT_UInt num, end, nn;
+ FT_Error error = FT_Err_Ok;
+
+
+ if ( !face )
+ return FT_Err_Invalid_Face_Handle;
+
+ num = (FT_UInt)face->num_glyphs;
+ end = start + count;
+ if ( start >= num || end < start || end > num )
+ return FT_Err_Invalid_Glyph_Index;
+
+ if ( count == 0 )
+ return FT_Err_Ok;
+
+ func = face->driver->clazz->get_advances;
+ if ( func && LOAD_ADVANCE_FAST_CHECK( flags ) )
+ {
+ error = func( face, start, count, flags, padvances );
+ if ( !error )
+ goto Exit;
+
+ if ( error != FT_ERROR_BASE( FT_Err_Unimplemented_Feature ) )
+ return error;
+ }
+
+ error = FT_Err_Ok;
+
+ if ( flags & FT_ADVANCE_FLAG_FAST_ONLY )
+ return FT_Err_Unimplemented_Feature;
+
+ flags |= FT_LOAD_ADVANCE_ONLY;
+ for ( nn = 0; nn < count; nn++ )
+ {
+ error = FT_Load_Glyph( face, start + nn, flags );
+ if ( error )
+ break;
+
+ padvances[nn] = ( flags & FT_LOAD_VERTICAL_LAYOUT )
+ ? face->glyph->advance.y
+ : face->glyph->advance.x;
+ }
+
+ if ( error )
+ return error;
+
+ Exit:
+ return _ft_face_scale_advances( face, padvances, count, flags );
+ }
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/base/ftapi.c b/src/3rdparty/freetype/src/base/ftapi.c
new file mode 100644
index 0000000000..8914d1f4e9
--- /dev/null
+++ b/src/3rdparty/freetype/src/base/ftapi.c
@@ -0,0 +1,121 @@
+/***************************************************************************/
+/* */
+/* ftapi.c */
+/* */
+/* The FreeType compatibility functions (body). */
+/* */
+/* Copyright 2002 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_LIST_H
+#include FT_OUTLINE_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_TRUETYPE_TABLES_H
+#include FT_OUTLINE_H
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** ****/
+ /**** C O M P A T I B I L I T Y ****/
+ /**** ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* backwards compatibility API */
+
+ FT_BASE_DEF( void )
+ FT_New_Memory_Stream( FT_Library library,
+ FT_Byte* base,
+ FT_ULong size,
+ FT_Stream stream )
+ {
+ FT_UNUSED( library );
+
+ FT_Stream_OpenMemory( stream, base, size );
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Seek_Stream( FT_Stream stream,
+ FT_ULong pos )
+ {
+ return FT_Stream_Seek( stream, pos );
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Skip_Stream( FT_Stream stream,
+ FT_Long distance )
+ {
+ return FT_Stream_Skip( stream, distance );
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Read_Stream( FT_Stream stream,
+ FT_Byte* buffer,
+ FT_ULong count )
+ {
+ return FT_Stream_Read( stream, buffer, count );
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Read_Stream_At( FT_Stream stream,
+ FT_ULong pos,
+ FT_Byte* buffer,
+ FT_ULong count )
+ {
+ return FT_Stream_ReadAt( stream, pos, buffer, count );
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_Extract_Frame( FT_Stream stream,
+ FT_ULong count,
+ FT_Byte** pbytes )
+ {
+ return FT_Stream_ExtractFrame( stream, count, pbytes );
+ }
+
+
+ FT_BASE_DEF( void )
+ FT_Release_Frame( FT_Stream stream,
+ FT_Byte** pbytes )
+ {
+ FT_Stream_ReleaseFrame( stream, pbytes );
+ }
+
+ FT_BASE_DEF( FT_Error )
+ FT_Access_Frame( FT_Stream stream,
+ FT_ULong count )
+ {
+ return FT_Stream_EnterFrame( stream, count );
+ }
+
+
+ FT_BASE_DEF( void )
+ FT_Forget_Frame( FT_Stream stream )
+ {
+ FT_Stream_ExitFrame( stream );
+ }
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/base/ftbase.c b/src/3rdparty/freetype/src/base/ftbase.c
new file mode 100644
index 0000000000..d1fe6e6088
--- /dev/null
+++ b/src/3rdparty/freetype/src/base/ftbase.c
@@ -0,0 +1,39 @@
+/***************************************************************************/
+/* */
+/* ftbase.c */
+/* */
+/* Single object library component (body only). */
+/* */
+/* Copyright 1996-2001, 2002, 2003, 2004, 2006, 2007, 2008 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include "ftadvanc.c"
+#include "ftcalc.c"
+#include "ftdbgmem.c"
+#include "ftgloadr.c"
+#include "ftnames.c"
+#include "ftobjs.c"
+#include "ftoutln.c"
+#include "ftrfork.c"
+#include "ftstream.c"
+#include "fttrigon.c"
+#include "ftutil.c"
+
+#if defined( FT_MACINTOSH ) && !defined ( DARWIN_NO_CARBON )
+#include "ftmac.c"
+#endif
+
+/* END */
diff --git a/src/3rdparty/freetype/src/base/ftbase.h b/src/3rdparty/freetype/src/base/ftbase.h
new file mode 100644
index 0000000000..9cae85da9e
--- /dev/null
+++ b/src/3rdparty/freetype/src/base/ftbase.h
@@ -0,0 +1,57 @@
+/***************************************************************************/
+/* */
+/* ftbase.h */
+/* */
+/* The FreeType private functions used in base module (specification). */
+/* */
+/* Copyright 2008 by */
+/* David Turner, Robert Wilhelm, Werner Lemberg, and suzuki toshiya. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#ifndef __FTBASE_H__
+#define __FTBASE_H__
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+
+
+FT_BEGIN_HEADER
+
+
+ /* Assume the stream is sfnt-wrapped PS Type1 or sfnt-wrapped CID-keyed */
+ /* font, and try to load a face specified by the face_index. */
+ FT_LOCAL_DEF( FT_Error )
+ open_face_PS_from_sfnt_stream( FT_Library library,
+ FT_Stream stream,
+ FT_Long face_index,
+ FT_Int num_params,
+ FT_Parameter *params,
+ FT_Face *aface );
+
+
+ /* Create a new FT_Face given a buffer and a driver name. */
+ /* From ftmac.c. */
+ FT_LOCAL_DEF( FT_Error )
+ open_face_from_buffer( FT_Library library,
+ FT_Byte* base,
+ FT_ULong size,
+ FT_Long face_index,
+ const char* driver_name,
+ FT_Face *aface );
+
+
+FT_END_HEADER
+
+#endif /* __FTBASE_H__ */
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/base/ftbbox.c b/src/3rdparty/freetype/src/base/ftbbox.c
new file mode 100644
index 0000000000..532ab13579
--- /dev/null
+++ b/src/3rdparty/freetype/src/base/ftbbox.c
@@ -0,0 +1,659 @@
+/***************************************************************************/
+/* */
+/* ftbbox.c */
+/* */
+/* FreeType bbox computation (body). */
+/* */
+/* Copyright 1996-2001, 2002, 2004, 2006 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used */
+/* modified and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This component has a _single_ role: to compute exact outline bounding */
+ /* boxes. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_BBOX_H
+#include FT_IMAGE_H
+#include FT_OUTLINE_H
+#include FT_INTERNAL_CALC_H
+
+
+ typedef struct TBBox_Rec_
+ {
+ FT_Vector last;
+ FT_BBox bbox;
+
+ } TBBox_Rec;
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* BBox_Move_To */
+ /* */
+ /* <Description> */
+ /* This function is used as a `move_to' and `line_to' emitter during */
+ /* FT_Outline_Decompose(). It simply records the destination point */
+ /* in `user->last'; no further computations are necessary since we */
+ /* use the cbox as the starting bbox which must be refined. */
+ /* */
+ /* <Input> */
+ /* to :: A pointer to the destination vector. */
+ /* */
+ /* <InOut> */
+ /* user :: A pointer to the current walk context. */
+ /* */
+ /* <Return> */
+ /* Always 0. Needed for the interface only. */
+ /* */
+ static int
+ BBox_Move_To( FT_Vector* to,
+ TBBox_Rec* user )
+ {
+ user->last = *to;
+
+ return 0;
+ }
+
+
+#define CHECK_X( p, bbox ) \
+ ( p->x < bbox.xMin || p->x > bbox.xMax )
+
+#define CHECK_Y( p, bbox ) \
+ ( p->y < bbox.yMin || p->y > bbox.yMax )
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* BBox_Conic_Check */
+ /* */
+ /* <Description> */
+ /* Finds the extrema of a 1-dimensional conic Bezier curve and update */
+ /* a bounding range. This version uses direct computation, as it */
+ /* doesn't need square roots. */
+ /* */
+ /* <Input> */
+ /* y1 :: The start coordinate. */
+ /* */
+ /* y2 :: The coordinate of the control point. */
+ /* */
+ /* y3 :: The end coordinate. */
+ /* */
+ /* <InOut> */
+ /* min :: The address of the current minimum. */
+ /* */
+ /* max :: The address of the current maximum. */
+ /* */
+ static void
+ BBox_Conic_Check( FT_Pos y1,
+ FT_Pos y2,
+ FT_Pos y3,
+ FT_Pos* min,
+ FT_Pos* max )
+ {
+ if ( y1 <= y3 && y2 == y1 ) /* flat arc */
+ goto Suite;
+
+ if ( y1 < y3 )
+ {
+ if ( y2 >= y1 && y2 <= y3 ) /* ascending arc */
+ goto Suite;
+ }
+ else
+ {
+ if ( y2 >= y3 && y2 <= y1 ) /* descending arc */
+ {
+ y2 = y1;
+ y1 = y3;
+ y3 = y2;
+ goto Suite;
+ }
+ }
+
+ y1 = y3 = y1 - FT_MulDiv( y2 - y1, y2 - y1, y1 - 2*y2 + y3 );
+
+ Suite:
+ if ( y1 < *min ) *min = y1;
+ if ( y3 > *max ) *max = y3;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* BBox_Conic_To */
+ /* */
+ /* <Description> */
+ /* This function is used as a `conic_to' emitter during */
+ /* FT_Raster_Decompose(). It checks a conic Bezier curve with the */
+ /* current bounding box, and computes its extrema if necessary to */
+ /* update it. */
+ /* */
+ /* <Input> */
+ /* control :: A pointer to a control point. */
+ /* */
+ /* to :: A pointer to the destination vector. */
+ /* */
+ /* <InOut> */
+ /* user :: The address of the current walk context. */
+ /* */
+ /* <Return> */
+ /* Always 0. Needed for the interface only. */
+ /* */
+ /* <Note> */
+ /* In the case of a non-monotonous arc, we compute directly the */
+ /* extremum coordinates, as it is sufficiently fast. */
+ /* */
+ static int
+ BBox_Conic_To( FT_Vector* control,
+ FT_Vector* to,
+ TBBox_Rec* user )
+ {
+ /* we don't need to check `to' since it is always an `on' point, thus */
+ /* within the bbox */
+
+ if ( CHECK_X( control, user->bbox ) )
+ BBox_Conic_Check( user->last.x,
+ control->x,
+ to->x,
+ &user->bbox.xMin,
+ &user->bbox.xMax );
+
+ if ( CHECK_Y( control, user->bbox ) )
+ BBox_Conic_Check( user->last.y,
+ control->y,
+ to->y,
+ &user->bbox.yMin,
+ &user->bbox.yMax );
+
+ user->last = *to;
+
+ return 0;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* BBox_Cubic_Check */
+ /* */
+ /* <Description> */
+ /* Finds the extrema of a 1-dimensional cubic Bezier curve and */
+ /* updates a bounding range. This version uses splitting because we */
+ /* don't want to use square roots and extra accuracy. */
+ /* */
+ /* <Input> */
+ /* p1 :: The start coordinate. */
+ /* */
+ /* p2 :: The coordinate of the first control point. */
+ /* */
+ /* p3 :: The coordinate of the second control point. */
+ /* */
+ /* p4 :: The end coordinate. */
+ /* */
+ /* <InOut> */
+ /* min :: The address of the current minimum. */
+ /* */
+ /* max :: The address of the current maximum. */
+ /* */
+
+#if 0
+
+ static void
+ BBox_Cubic_Check( FT_Pos p1,
+ FT_Pos p2,
+ FT_Pos p3,
+ FT_Pos p4,
+ FT_Pos* min,
+ FT_Pos* max )
+ {
+ FT_Pos stack[32*3 + 1], *arc;
+
+
+ arc = stack;
+
+ arc[0] = p1;
+ arc[1] = p2;
+ arc[2] = p3;
+ arc[3] = p4;
+
+ do
+ {
+ FT_Pos y1 = arc[0];
+ FT_Pos y2 = arc[1];
+ FT_Pos y3 = arc[2];
+ FT_Pos y4 = arc[3];
+
+
+ if ( y1 == y4 )
+ {
+ if ( y1 == y2 && y1 == y3 ) /* flat */
+ goto Test;
+ }
+ else if ( y1 < y4 )
+ {
+ if ( y2 >= y1 && y2 <= y4 && y3 >= y1 && y3 <= y4 ) /* ascending */
+ goto Test;
+ }
+ else
+ {
+ if ( y2 >= y4 && y2 <= y1 && y3 >= y4 && y3 <= y1 ) /* descending */
+ {
+ y2 = y1;
+ y1 = y4;
+ y4 = y2;
+ goto Test;
+ }
+ }
+
+ /* unknown direction -- split the arc in two */
+ arc[6] = y4;
+ arc[1] = y1 = ( y1 + y2 ) / 2;
+ arc[5] = y4 = ( y4 + y3 ) / 2;
+ y2 = ( y2 + y3 ) / 2;
+ arc[2] = y1 = ( y1 + y2 ) / 2;
+ arc[4] = y4 = ( y4 + y2 ) / 2;
+ arc[3] = ( y1 + y4 ) / 2;
+
+ arc += 3;
+ goto Suite;
+
+ Test:
+ if ( y1 < *min ) *min = y1;
+ if ( y4 > *max ) *max = y4;
+ arc -= 3;
+
+ Suite:
+ ;
+ } while ( arc >= stack );
+ }
+
+#else
+
+ static void
+ test_cubic_extrema( FT_Pos y1,
+ FT_Pos y2,
+ FT_Pos y3,
+ FT_Pos y4,
+ FT_Fixed u,
+ FT_Pos* min,
+ FT_Pos* max )
+ {
+ /* FT_Pos a = y4 - 3*y3 + 3*y2 - y1; */
+ FT_Pos b = y3 - 2*y2 + y1;
+ FT_Pos c = y2 - y1;
+ FT_Pos d = y1;
+ FT_Pos y;
+ FT_Fixed uu;
+
+ FT_UNUSED ( y4 );
+
+
+ /* The polynomial is */
+ /* */
+ /* P(x) = a*x^3 + 3b*x^2 + 3c*x + d , */
+ /* */
+ /* dP/dx = 3a*x^2 + 6b*x + 3c . */
+ /* */
+ /* However, we also have */
+ /* */
+ /* dP/dx(u) = 0 , */
+ /* */
+ /* which implies by subtraction that */
+ /* */
+ /* P(u) = b*u^2 + 2c*u + d . */
+
+ if ( u > 0 && u < 0x10000L )
+ {
+ uu = FT_MulFix( u, u );
+ y = d + FT_MulFix( c, 2*u ) + FT_MulFix( b, uu );
+
+ if ( y < *min ) *min = y;
+ if ( y > *max ) *max = y;
+ }
+ }
+
+
+ static void
+ BBox_Cubic_Check( FT_Pos y1,
+ FT_Pos y2,
+ FT_Pos y3,
+ FT_Pos y4,
+ FT_Pos* min,
+ FT_Pos* max )
+ {
+ /* always compare first and last points */
+ if ( y1 < *min ) *min = y1;
+ else if ( y1 > *max ) *max = y1;
+
+ if ( y4 < *min ) *min = y4;
+ else if ( y4 > *max ) *max = y4;
+
+ /* now, try to see if there are split points here */
+ if ( y1 <= y4 )
+ {
+ /* flat or ascending arc test */
+ if ( y1 <= y2 && y2 <= y4 && y1 <= y3 && y3 <= y4 )
+ return;
+ }
+ else /* y1 > y4 */
+ {
+ /* descending arc test */
+ if ( y1 >= y2 && y2 >= y4 && y1 >= y3 && y3 >= y4 )
+ return;
+ }
+
+ /* There are some split points. Find them. */
+ {
+ FT_Pos a = y4 - 3*y3 + 3*y2 - y1;
+ FT_Pos b = y3 - 2*y2 + y1;
+ FT_Pos c = y2 - y1;
+ FT_Pos d;
+ FT_Fixed t;
+
+
+ /* We need to solve `ax^2+2bx+c' here, without floating points! */
+ /* The trick is to normalize to a different representation in order */
+ /* to use our 16.16 fixed point routines. */
+ /* */
+ /* We compute FT_MulFix(b,b) and FT_MulFix(a,c) after normalization. */
+ /* These values must fit into a single 16.16 value. */
+ /* */
+ /* We normalize a, b, and c to `8.16' fixed float values to ensure */
+ /* that its product is held in a `16.16' value. */
+
+ {
+ FT_ULong t1, t2;
+ int shift = 0;
+
+
+ /* The following computation is based on the fact that for */
+ /* any value `y', if `n' is the position of the most */
+ /* significant bit of `abs(y)' (starting from 0 for the */
+ /* least significant bit), then `y' is in the range */
+ /* */
+ /* -2^n..2^n-1 */
+ /* */
+ /* We want to shift `a', `b', and `c' concurrently in order */
+ /* to ensure that they all fit in 8.16 values, which maps */
+ /* to the integer range `-2^23..2^23-1'. */
+ /* */
+ /* Necessarily, we need to shift `a', `b', and `c' so that */
+ /* the most significant bit of its absolute values is at */
+ /* _most_ at position 23. */
+ /* */
+ /* We begin by computing `t1' as the bitwise `OR' of the */
+ /* absolute values of `a', `b', `c'. */
+
+ t1 = (FT_ULong)( ( a >= 0 ) ? a : -a );
+ t2 = (FT_ULong)( ( b >= 0 ) ? b : -b );
+ t1 |= t2;
+ t2 = (FT_ULong)( ( c >= 0 ) ? c : -c );
+ t1 |= t2;
+
+ /* Now we can be sure that the most significant bit of `t1' */
+ /* is the most significant bit of either `a', `b', or `c', */
+ /* depending on the greatest integer range of the particular */
+ /* variable. */
+ /* */
+ /* Next, we compute the `shift', by shifting `t1' as many */
+ /* times as necessary to move its MSB to position 23. This */
+ /* corresponds to a value of `t1' that is in the range */
+ /* 0x40_0000..0x7F_FFFF. */
+ /* */
+ /* Finally, we shift `a', `b', and `c' by the same amount. */
+ /* This ensures that all values are now in the range */
+ /* -2^23..2^23, i.e., they are now expressed as 8.16 */
+ /* fixed-float numbers. This also means that we are using */
+ /* 24 bits of precision to compute the zeros, independently */
+ /* of the range of the original polynomial coefficients. */
+ /* */
+ /* This algorithm should ensure reasonably accurate values */
+ /* for the zeros. Note that they are only expressed with */
+ /* 16 bits when computing the extrema (the zeros need to */
+ /* be in 0..1 exclusive to be considered part of the arc). */
+
+ if ( t1 == 0 ) /* all coefficients are 0! */
+ return;
+
+ if ( t1 > 0x7FFFFFUL )
+ {
+ do
+ {
+ shift++;
+ t1 >>= 1;
+
+ } while ( t1 > 0x7FFFFFUL );
+
+ /* this loses some bits of precision, but we use 24 of them */
+ /* for the computation anyway */
+ a >>= shift;
+ b >>= shift;
+ c >>= shift;
+ }
+ else if ( t1 < 0x400000UL )
+ {
+ do
+ {
+ shift++;
+ t1 <<= 1;
+
+ } while ( t1 < 0x400000UL );
+
+ a <<= shift;
+ b <<= shift;
+ c <<= shift;
+ }
+ }
+
+ /* handle a == 0 */
+ if ( a == 0 )
+ {
+ if ( b != 0 )
+ {
+ t = - FT_DivFix( c, b ) / 2;
+ test_cubic_extrema( y1, y2, y3, y4, t, min, max );
+ }
+ }
+ else
+ {
+ /* solve the equation now */
+ d = FT_MulFix( b, b ) - FT_MulFix( a, c );
+ if ( d < 0 )
+ return;
+
+ if ( d == 0 )
+ {
+ /* there is a single split point at -b/a */
+ t = - FT_DivFix( b, a );
+ test_cubic_extrema( y1, y2, y3, y4, t, min, max );
+ }
+ else
+ {
+ /* there are two solutions; we need to filter them */
+ d = FT_SqrtFixed( (FT_Int32)d );
+ t = - FT_DivFix( b - d, a );
+ test_cubic_extrema( y1, y2, y3, y4, t, min, max );
+
+ t = - FT_DivFix( b + d, a );
+ test_cubic_extrema( y1, y2, y3, y4, t, min, max );
+ }
+ }
+ }
+ }
+
+#endif
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* BBox_Cubic_To */
+ /* */
+ /* <Description> */
+ /* This function is used as a `cubic_to' emitter during */
+ /* FT_Raster_Decompose(). It checks a cubic Bezier curve with the */
+ /* current bounding box, and computes its extrema if necessary to */
+ /* update it. */
+ /* */
+ /* <Input> */
+ /* control1 :: A pointer to the first control point. */
+ /* */
+ /* control2 :: A pointer to the second control point. */
+ /* */
+ /* to :: A pointer to the destination vector. */
+ /* */
+ /* <InOut> */
+ /* user :: The address of the current walk context. */
+ /* */
+ /* <Return> */
+ /* Always 0. Needed for the interface only. */
+ /* */
+ /* <Note> */
+ /* In the case of a non-monotonous arc, we don't compute directly */
+ /* extremum coordinates, we subdivide instead. */
+ /* */
+ static int
+ BBox_Cubic_To( FT_Vector* control1,
+ FT_Vector* control2,
+ FT_Vector* to,
+ TBBox_Rec* user )
+ {
+ /* we don't need to check `to' since it is always an `on' point, thus */
+ /* within the bbox */
+
+ if ( CHECK_X( control1, user->bbox ) ||
+ CHECK_X( control2, user->bbox ) )
+ BBox_Cubic_Check( user->last.x,
+ control1->x,
+ control2->x,
+ to->x,
+ &user->bbox.xMin,
+ &user->bbox.xMax );
+
+ if ( CHECK_Y( control1, user->bbox ) ||
+ CHECK_Y( control2, user->bbox ) )
+ BBox_Cubic_Check( user->last.y,
+ control1->y,
+ control2->y,
+ to->y,
+ &user->bbox.yMin,
+ &user->bbox.yMax );
+
+ user->last = *to;
+
+ return 0;
+ }
+
+
+ /* documentation is in ftbbox.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Outline_Get_BBox( FT_Outline* outline,
+ FT_BBox *abbox )
+ {
+ FT_BBox cbox;
+ FT_BBox bbox;
+ FT_Vector* vec;
+ FT_UShort n;
+
+
+ if ( !abbox )
+ return FT_Err_Invalid_Argument;
+
+ if ( !outline )
+ return FT_Err_Invalid_Outline;
+
+ /* if outline is empty, return (0,0,0,0) */
+ if ( outline->n_points == 0 || outline->n_contours <= 0 )
+ {
+ abbox->xMin = abbox->xMax = 0;
+ abbox->yMin = abbox->yMax = 0;
+ return 0;
+ }
+
+ /* We compute the control box as well as the bounding box of */
+ /* all `on' points in the outline. Then, if the two boxes */
+ /* coincide, we exit immediately. */
+
+ vec = outline->points;
+ bbox.xMin = bbox.xMax = cbox.xMin = cbox.xMax = vec->x;
+ bbox.yMin = bbox.yMax = cbox.yMin = cbox.yMax = vec->y;
+ vec++;
+
+ for ( n = 1; n < outline->n_points; n++ )
+ {
+ FT_Pos x = vec->x;
+ FT_Pos y = vec->y;
+
+
+ /* update control box */
+ if ( x < cbox.xMin ) cbox.xMin = x;
+ if ( x > cbox.xMax ) cbox.xMax = x;
+
+ if ( y < cbox.yMin ) cbox.yMin = y;
+ if ( y > cbox.yMax ) cbox.yMax = y;
+
+ if ( FT_CURVE_TAG( outline->tags[n] ) == FT_CURVE_TAG_ON )
+ {
+ /* update bbox for `on' points only */
+ if ( x < bbox.xMin ) bbox.xMin = x;
+ if ( x > bbox.xMax ) bbox.xMax = x;
+
+ if ( y < bbox.yMin ) bbox.yMin = y;
+ if ( y > bbox.yMax ) bbox.yMax = y;
+ }
+
+ vec++;
+ }
+
+ /* test two boxes for equality */
+ if ( cbox.xMin < bbox.xMin || cbox.xMax > bbox.xMax ||
+ cbox.yMin < bbox.yMin || cbox.yMax > bbox.yMax )
+ {
+ /* the two boxes are different, now walk over the outline to */
+ /* get the Bezier arc extrema. */
+
+ static const FT_Outline_Funcs bbox_interface =
+ {
+ (FT_Outline_MoveTo_Func) BBox_Move_To,
+ (FT_Outline_LineTo_Func) BBox_Move_To,
+ (FT_Outline_ConicTo_Func)BBox_Conic_To,
+ (FT_Outline_CubicTo_Func)BBox_Cubic_To,
+ 0, 0
+ };
+
+ FT_Error error;
+ TBBox_Rec user;
+
+
+ user.bbox = bbox;
+
+ error = FT_Outline_Decompose( outline, &bbox_interface, &user );
+ if ( error )
+ return error;
+
+ *abbox = user.bbox;
+ }
+ else
+ *abbox = bbox;
+
+ return FT_Err_Ok;
+ }
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/base/ftbdf.c b/src/3rdparty/freetype/src/base/ftbdf.c
new file mode 100644
index 0000000000..d29adf09dd
--- /dev/null
+++ b/src/3rdparty/freetype/src/base/ftbdf.c
@@ -0,0 +1,88 @@
+/***************************************************************************/
+/* */
+/* ftbdf.c */
+/* */
+/* FreeType API for accessing BDF-specific strings (body). */
+/* */
+/* Copyright 2002, 2003, 2004 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_SERVICE_BDF_H
+
+
+ /* documentation is in ftbdf.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_BDF_Charset_ID( FT_Face face,
+ const char* *acharset_encoding,
+ const char* *acharset_registry )
+ {
+ FT_Error error;
+ const char* encoding = NULL;
+ const char* registry = NULL;
+
+
+ error = FT_Err_Invalid_Argument;
+
+ if ( face )
+ {
+ FT_Service_BDF service;
+
+
+ FT_FACE_FIND_SERVICE( face, service, BDF );
+
+ if ( service && service->get_charset_id )
+ error = service->get_charset_id( face, &encoding, &registry );
+ }
+
+ if ( acharset_encoding )
+ *acharset_encoding = encoding;
+
+ if ( acharset_registry )
+ *acharset_registry = registry;
+
+ return error;
+ }
+
+
+ /* documentation is in ftbdf.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_BDF_Property( FT_Face face,
+ const char* prop_name,
+ BDF_PropertyRec *aproperty )
+ {
+ FT_Error error;
+
+
+ error = FT_Err_Invalid_Argument;
+
+ aproperty->type = BDF_PROPERTY_TYPE_NONE;
+
+ if ( face )
+ {
+ FT_Service_BDF service;
+
+
+ FT_FACE_FIND_SERVICE( face, service, BDF );
+
+ if ( service && service->get_property )
+ error = service->get_property( face, prop_name, aproperty );
+ }
+
+ return error;
+ }
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/base/ftbitmap.c b/src/3rdparty/freetype/src/base/ftbitmap.c
new file mode 100644
index 0000000000..8810cfadf3
--- /dev/null
+++ b/src/3rdparty/freetype/src/base/ftbitmap.c
@@ -0,0 +1,659 @@
+/***************************************************************************/
+/* */
+/* ftbitmap.c */
+/* */
+/* FreeType utility functions for bitmaps (body). */
+/* */
+/* Copyright 2004, 2005, 2006, 2007, 2008, 2009 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_BITMAP_H
+#include FT_IMAGE_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+ static
+ const FT_Bitmap null_bitmap = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+
+ /* documentation is in ftbitmap.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Bitmap_New( FT_Bitmap *abitmap )
+ {
+ *abitmap = null_bitmap;
+ }
+
+
+ /* documentation is in ftbitmap.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Bitmap_Copy( FT_Library library,
+ const FT_Bitmap *source,
+ FT_Bitmap *target)
+ {
+ FT_Memory memory = library->memory;
+ FT_Error error = FT_Err_Ok;
+ FT_Int pitch = source->pitch;
+ FT_ULong size;
+
+
+ if ( source == target )
+ return FT_Err_Ok;
+
+ if ( source->buffer == NULL )
+ {
+ *target = *source;
+
+ return FT_Err_Ok;
+ }
+
+ if ( pitch < 0 )
+ pitch = -pitch;
+ size = (FT_ULong)( pitch * source->rows );
+
+ if ( target->buffer )
+ {
+ FT_Int target_pitch = target->pitch;
+ FT_ULong target_size;
+
+
+ if ( target_pitch < 0 )
+ target_pitch = -target_pitch;
+ target_size = (FT_ULong)( target_pitch * target->rows );
+
+ if ( target_size != size )
+ (void)FT_QREALLOC( target->buffer, target_size, size );
+ }
+ else
+ (void)FT_QALLOC( target->buffer, size );
+
+ if ( !error )
+ {
+ unsigned char *p;
+
+
+ p = target->buffer;
+ *target = *source;
+ target->buffer = p;
+
+ FT_MEM_COPY( target->buffer, source->buffer, size );
+ }
+
+ return error;
+ }
+
+
+ static FT_Error
+ ft_bitmap_assure_buffer( FT_Memory memory,
+ FT_Bitmap* bitmap,
+ FT_UInt xpixels,
+ FT_UInt ypixels )
+ {
+ FT_Error error;
+ int pitch;
+ int new_pitch;
+ FT_UInt bpp;
+ FT_Int i, width, height;
+ unsigned char* buffer;
+
+
+ width = bitmap->width;
+ height = bitmap->rows;
+ pitch = bitmap->pitch;
+ if ( pitch < 0 )
+ pitch = -pitch;
+
+ switch ( bitmap->pixel_mode )
+ {
+ case FT_PIXEL_MODE_MONO:
+ bpp = 1;
+ new_pitch = ( width + xpixels + 7 ) >> 3;
+ break;
+ case FT_PIXEL_MODE_GRAY2:
+ bpp = 2;
+ new_pitch = ( width + xpixels + 3 ) >> 2;
+ break;
+ case FT_PIXEL_MODE_GRAY4:
+ bpp = 4;
+ new_pitch = ( width + xpixels + 1 ) >> 1;
+ break;
+ case FT_PIXEL_MODE_GRAY:
+ case FT_PIXEL_MODE_LCD:
+ case FT_PIXEL_MODE_LCD_V:
+ bpp = 8;
+ new_pitch = ( width + xpixels );
+ break;
+ default:
+ return FT_Err_Invalid_Glyph_Format;
+ }
+
+ /* if no need to allocate memory */
+ if ( ypixels == 0 && new_pitch <= pitch )
+ {
+ /* zero the padding */
+ FT_Int bit_width = pitch * 8;
+ FT_Int bit_last = ( width + xpixels ) * bpp;
+
+
+ if ( bit_last < bit_width )
+ {
+ FT_Byte* line = bitmap->buffer + ( bit_last >> 3 );
+ FT_Byte* end = bitmap->buffer + pitch;
+ FT_Int shift = bit_last & 7;
+ FT_UInt mask = 0xFF00U >> shift;
+ FT_Int count = height;
+
+
+ for ( ; count > 0; count--, line += pitch, end += pitch )
+ {
+ FT_Byte* write = line;
+
+
+ if ( shift > 0 )
+ {
+ write[0] = (FT_Byte)( write[0] & mask );
+ write++;
+ }
+ if ( write < end )
+ FT_MEM_ZERO( write, end-write );
+ }
+ }
+
+ return FT_Err_Ok;
+ }
+
+ if ( FT_QALLOC_MULT( buffer, new_pitch, bitmap->rows + ypixels ) )
+ return error;
+
+ if ( bitmap->pitch > 0 )
+ {
+ FT_Int len = ( width * bpp + 7 ) >> 3;
+
+
+ for ( i = 0; i < bitmap->rows; i++ )
+ FT_MEM_COPY( buffer + new_pitch * ( ypixels + i ),
+ bitmap->buffer + pitch * i, len );
+ }
+ else
+ {
+ FT_Int len = ( width * bpp + 7 ) >> 3;
+
+
+ for ( i = 0; i < bitmap->rows; i++ )
+ FT_MEM_COPY( buffer + new_pitch * i,
+ bitmap->buffer + pitch * i, len );
+ }
+
+ FT_FREE( bitmap->buffer );
+ bitmap->buffer = buffer;
+
+ if ( bitmap->pitch < 0 )
+ new_pitch = -new_pitch;
+
+ /* set pitch only, width and height are left untouched */
+ bitmap->pitch = new_pitch;
+
+ return FT_Err_Ok;
+ }
+
+
+ /* documentation is in ftbitmap.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Bitmap_Embolden( FT_Library library,
+ FT_Bitmap* bitmap,
+ FT_Pos xStrength,
+ FT_Pos yStrength )
+ {
+ FT_Error error;
+ unsigned char* p;
+ FT_Int i, x, y, pitch;
+ FT_Int xstr, ystr;
+
+
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ if ( !bitmap || !bitmap->buffer )
+ return FT_Err_Invalid_Argument;
+
+ xstr = FT_PIX_ROUND( xStrength ) >> 6;
+ ystr = FT_PIX_ROUND( yStrength ) >> 6;
+
+ if ( xstr == 0 && ystr == 0 )
+ return FT_Err_Ok;
+ else if ( xstr < 0 || ystr < 0 )
+ return FT_Err_Invalid_Argument;
+
+ switch ( bitmap->pixel_mode )
+ {
+ case FT_PIXEL_MODE_GRAY2:
+ case FT_PIXEL_MODE_GRAY4:
+ {
+ FT_Bitmap tmp;
+ FT_Int align;
+
+
+ if ( bitmap->pixel_mode == FT_PIXEL_MODE_GRAY2 )
+ align = ( bitmap->width + xstr + 3 ) / 4;
+ else
+ align = ( bitmap->width + xstr + 1 ) / 2;
+
+ FT_Bitmap_New( &tmp );
+
+ error = FT_Bitmap_Convert( library, bitmap, &tmp, align );
+ if ( error )
+ return error;
+
+ FT_Bitmap_Done( library, bitmap );
+ *bitmap = tmp;
+ }
+ break;
+
+ case FT_PIXEL_MODE_MONO:
+ if ( xstr > 8 )
+ xstr = 8;
+ break;
+
+ case FT_PIXEL_MODE_LCD:
+ xstr *= 3;
+ break;
+
+ case FT_PIXEL_MODE_LCD_V:
+ ystr *= 3;
+ break;
+ }
+
+ error = ft_bitmap_assure_buffer( library->memory, bitmap, xstr, ystr );
+ if ( error )
+ return error;
+
+ pitch = bitmap->pitch;
+ if ( pitch > 0 )
+ p = bitmap->buffer + pitch * ystr;
+ else
+ {
+ pitch = -pitch;
+ p = bitmap->buffer + pitch * ( bitmap->rows - 1 );
+ }
+
+ /* for each row */
+ for ( y = 0; y < bitmap->rows ; y++ )
+ {
+ /*
+ * Horizontally:
+ *
+ * From the last pixel on, make each pixel or'ed with the
+ * `xstr' pixels before it.
+ */
+ for ( x = pitch - 1; x >= 0; x-- )
+ {
+ unsigned char tmp;
+
+
+ tmp = p[x];
+ for ( i = 1; i <= xstr; i++ )
+ {
+ if ( bitmap->pixel_mode == FT_PIXEL_MODE_MONO )
+ {
+ p[x] |= tmp >> i;
+
+ /* the maximum value of 8 for `xstr' comes from here */
+ if ( x > 0 )
+ p[x] |= p[x - 1] << ( 8 - i );
+
+#if 0
+ if ( p[x] == 0xff )
+ break;
+#endif
+ }
+ else
+ {
+ if ( x - i >= 0 )
+ {
+ if ( p[x] + p[x - i] > bitmap->num_grays - 1 )
+ {
+ p[x] = (unsigned char)(bitmap->num_grays - 1);
+ break;
+ }
+ else
+ {
+ p[x] = (unsigned char)(p[x] + p[x-i]);
+ if ( p[x] == bitmap->num_grays - 1 )
+ break;
+ }
+ }
+ else
+ break;
+ }
+ }
+ }
+
+ /*
+ * Vertically:
+ *
+ * Make the above `ystr' rows or'ed with it.
+ */
+ for ( x = 1; x <= ystr; x++ )
+ {
+ unsigned char* q;
+
+
+ q = p - bitmap->pitch * x;
+ for ( i = 0; i < pitch; i++ )
+ q[i] |= p[i];
+ }
+
+ p += bitmap->pitch;
+ }
+
+ bitmap->width += xstr;
+ bitmap->rows += ystr;
+
+ return FT_Err_Ok;
+ }
+
+
+ /* documentation is in ftbitmap.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Bitmap_Convert( FT_Library library,
+ const FT_Bitmap *source,
+ FT_Bitmap *target,
+ FT_Int alignment )
+ {
+ FT_Error error = FT_Err_Ok;
+ FT_Memory memory;
+
+
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ memory = library->memory;
+
+ switch ( source->pixel_mode )
+ {
+ case FT_PIXEL_MODE_MONO:
+ case FT_PIXEL_MODE_GRAY:
+ case FT_PIXEL_MODE_GRAY2:
+ case FT_PIXEL_MODE_GRAY4:
+ case FT_PIXEL_MODE_LCD:
+ case FT_PIXEL_MODE_LCD_V:
+ {
+ FT_Int pad;
+ FT_Long old_size;
+
+
+ old_size = target->rows * target->pitch;
+ if ( old_size < 0 )
+ old_size = -old_size;
+
+ target->pixel_mode = FT_PIXEL_MODE_GRAY;
+ target->rows = source->rows;
+ target->width = source->width;
+
+ pad = 0;
+ if ( alignment > 0 )
+ {
+ pad = source->width % alignment;
+ if ( pad != 0 )
+ pad = alignment - pad;
+ }
+
+ target->pitch = source->width + pad;
+
+ if ( target->rows * target->pitch > old_size &&
+ FT_QREALLOC( target->buffer,
+ old_size, target->rows * target->pitch ) )
+ return error;
+ }
+ break;
+
+ default:
+ error = FT_Err_Invalid_Argument;
+ }
+
+ switch ( source->pixel_mode )
+ {
+ case FT_PIXEL_MODE_MONO:
+ {
+ FT_Byte* s = source->buffer;
+ FT_Byte* t = target->buffer;
+ FT_Int i;
+
+
+ target->num_grays = 2;
+
+ for ( i = source->rows; i > 0; i-- )
+ {
+ FT_Byte* ss = s;
+ FT_Byte* tt = t;
+ FT_Int j;
+
+
+ /* get the full bytes */
+ for ( j = source->width >> 3; j > 0; j-- )
+ {
+ FT_Int val = ss[0]; /* avoid a byte->int cast on each line */
+
+
+ tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7 );
+ tt[1] = (FT_Byte)( ( val & 0x40 ) >> 6 );
+ tt[2] = (FT_Byte)( ( val & 0x20 ) >> 5 );
+ tt[3] = (FT_Byte)( ( val & 0x10 ) >> 4 );
+ tt[4] = (FT_Byte)( ( val & 0x08 ) >> 3 );
+ tt[5] = (FT_Byte)( ( val & 0x04 ) >> 2 );
+ tt[6] = (FT_Byte)( ( val & 0x02 ) >> 1 );
+ tt[7] = (FT_Byte)( val & 0x01 );
+
+ tt += 8;
+ ss += 1;
+ }
+
+ /* get remaining pixels (if any) */
+ j = source->width & 7;
+ if ( j > 0 )
+ {
+ FT_Int val = *ss;
+
+
+ for ( ; j > 0; j-- )
+ {
+ tt[0] = (FT_Byte)( ( val & 0x80 ) >> 7);
+ val <<= 1;
+ tt += 1;
+ }
+ }
+
+ s += source->pitch;
+ t += target->pitch;
+ }
+ }
+ break;
+
+
+ case FT_PIXEL_MODE_GRAY:
+ case FT_PIXEL_MODE_LCD:
+ case FT_PIXEL_MODE_LCD_V:
+ {
+ FT_Int width = source->width;
+ FT_Byte* s = source->buffer;
+ FT_Byte* t = target->buffer;
+ FT_Int s_pitch = source->pitch;
+ FT_Int t_pitch = target->pitch;
+ FT_Int i;
+
+
+ target->num_grays = 256;
+
+ for ( i = source->rows; i > 0; i-- )
+ {
+ FT_ARRAY_COPY( t, s, width );
+
+ s += s_pitch;
+ t += t_pitch;
+ }
+ }
+ break;
+
+
+ case FT_PIXEL_MODE_GRAY2:
+ {
+ FT_Byte* s = source->buffer;
+ FT_Byte* t = target->buffer;
+ FT_Int i;
+
+
+ target->num_grays = 4;
+
+ for ( i = source->rows; i > 0; i-- )
+ {
+ FT_Byte* ss = s;
+ FT_Byte* tt = t;
+ FT_Int j;
+
+
+ /* get the full bytes */
+ for ( j = source->width >> 2; j > 0; j-- )
+ {
+ FT_Int val = ss[0];
+
+
+ tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 );
+ tt[1] = (FT_Byte)( ( val & 0x30 ) >> 4 );
+ tt[2] = (FT_Byte)( ( val & 0x0C ) >> 2 );
+ tt[3] = (FT_Byte)( ( val & 0x03 ) );
+
+ ss += 1;
+ tt += 4;
+ }
+
+ j = source->width & 3;
+ if ( j > 0 )
+ {
+ FT_Int val = ss[0];
+
+
+ for ( ; j > 0; j-- )
+ {
+ tt[0] = (FT_Byte)( ( val & 0xC0 ) >> 6 );
+ val <<= 2;
+ tt += 1;
+ }
+ }
+
+ s += source->pitch;
+ t += target->pitch;
+ }
+ }
+ break;
+
+
+ case FT_PIXEL_MODE_GRAY4:
+ {
+ FT_Byte* s = source->buffer;
+ FT_Byte* t = target->buffer;
+ FT_Int i;
+
+
+ target->num_grays = 16;
+
+ for ( i = source->rows; i > 0; i-- )
+ {
+ FT_Byte* ss = s;
+ FT_Byte* tt = t;
+ FT_Int j;
+
+
+ /* get the full bytes */
+ for ( j = source->width >> 1; j > 0; j-- )
+ {
+ FT_Int val = ss[0];
+
+
+ tt[0] = (FT_Byte)( ( val & 0xF0 ) >> 4 );
+ tt[1] = (FT_Byte)( ( val & 0x0F ) );
+
+ ss += 1;
+ tt += 2;
+ }
+
+ if ( source->width & 1 )
+ tt[0] = (FT_Byte)( ( ss[0] & 0xF0 ) >> 4 );
+
+ s += source->pitch;
+ t += target->pitch;
+ }
+ }
+ break;
+
+
+ default:
+ ;
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in ftbitmap.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_GlyphSlot_Own_Bitmap( FT_GlyphSlot slot )
+ {
+ if ( slot && slot->format == FT_GLYPH_FORMAT_BITMAP &&
+ !( slot->internal->flags & FT_GLYPH_OWN_BITMAP ) )
+ {
+ FT_Bitmap bitmap;
+ FT_Error error;
+
+
+ FT_Bitmap_New( &bitmap );
+ error = FT_Bitmap_Copy( slot->library, &slot->bitmap, &bitmap );
+ if ( error )
+ return error;
+
+ slot->bitmap = bitmap;
+ slot->internal->flags |= FT_GLYPH_OWN_BITMAP;
+ }
+
+ return FT_Err_Ok;
+ }
+
+
+ /* documentation is in ftbitmap.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Bitmap_Done( FT_Library library,
+ FT_Bitmap *bitmap )
+ {
+ FT_Memory memory;
+
+
+ if ( !library )
+ return FT_Err_Invalid_Library_Handle;
+
+ if ( !bitmap )
+ return FT_Err_Invalid_Argument;
+
+ memory = library->memory;
+
+ FT_FREE( bitmap->buffer );
+ *bitmap = null_bitmap;
+
+ return FT_Err_Ok;
+ }
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/base/ftcalc.c b/src/3rdparty/freetype/src/base/ftcalc.c
new file mode 100644
index 0000000000..04295a6931
--- /dev/null
+++ b/src/3rdparty/freetype/src/base/ftcalc.c
@@ -0,0 +1,953 @@
+/***************************************************************************/
+/* */
+/* ftcalc.c */
+/* */
+/* Arithmetic computations (body). */
+/* */
+/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2008 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* Support for 1-complement arithmetic has been totally dropped in this */
+ /* release. You can still write your own code if you need it. */
+ /* */
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* Implementing basic computation routines. */
+ /* */
+ /* FT_MulDiv(), FT_MulFix(), FT_DivFix(), FT_RoundFix(), FT_CeilFix(), */
+ /* and FT_FloorFix() are declared in freetype.h. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_GLYPH_H
+#include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_OBJECTS_H
+
+#ifdef FT_MULFIX_INLINED
+#undef FT_MulFix
+#endif
+
+/* we need to define a 64-bits data type here */
+
+#ifdef FT_LONG64
+
+ typedef FT_INT64 FT_Int64;
+
+#else
+
+ typedef struct FT_Int64_
+ {
+ FT_UInt32 lo;
+ FT_UInt32 hi;
+
+ } FT_Int64;
+
+#endif /* FT_LONG64 */
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_calc
+
+
+ /* The following three functions are available regardless of whether */
+ /* FT_LONG64 is defined. */
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Fixed )
+ FT_RoundFix( FT_Fixed a )
+ {
+ return ( a >= 0 ) ? ( a + 0x8000L ) & ~0xFFFFL
+ : -((-a + 0x8000L ) & ~0xFFFFL );
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Fixed )
+ FT_CeilFix( FT_Fixed a )
+ {
+ return ( a >= 0 ) ? ( a + 0xFFFFL ) & ~0xFFFFL
+ : -((-a + 0xFFFFL ) & ~0xFFFFL );
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Fixed )
+ FT_FloorFix( FT_Fixed a )
+ {
+ return ( a >= 0 ) ? a & ~0xFFFFL
+ : -((-a) & ~0xFFFFL );
+ }
+
+
+#ifdef FT_CONFIG_OPTION_OLD_INTERNALS
+
+ /* documentation is in ftcalc.h */
+
+ FT_EXPORT_DEF( FT_Int32 )
+ FT_Sqrt32( FT_Int32 x )
+ {
+ FT_ULong val, root, newroot, mask;
+
+
+ root = 0;
+ mask = 0x40000000L;
+ val = (FT_ULong)x;
+
+ do
+ {
+ newroot = root + mask;
+ if ( newroot <= val )
+ {
+ val -= newroot;
+ root = newroot + mask;
+ }
+
+ root >>= 1;
+ mask >>= 2;
+
+ } while ( mask != 0 );
+
+ return root;
+ }
+
+#endif /* FT_CONFIG_OPTION_OLD_INTERNALS */
+
+
+#ifdef FT_LONG64
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Long )
+ FT_MulDiv( FT_Long a,
+ FT_Long b,
+ FT_Long c )
+ {
+ FT_Int s;
+ FT_Long d;
+
+
+ s = 1;
+ if ( a < 0 ) { a = -a; s = -1; }
+ if ( b < 0 ) { b = -b; s = -s; }
+ if ( c < 0 ) { c = -c; s = -s; }
+
+ d = (FT_Long)( c > 0 ? ( (FT_Int64)a * b + ( c >> 1 ) ) / c
+ : 0x7FFFFFFFL );
+
+ return ( s > 0 ) ? d : -d;
+ }
+
+
+#ifdef TT_USE_BYTECODE_INTERPRETER
+
+ /* documentation is in ftcalc.h */
+
+ FT_BASE_DEF( FT_Long )
+ FT_MulDiv_No_Round( FT_Long a,
+ FT_Long b,
+ FT_Long c )
+ {
+ FT_Int s;
+ FT_Long d;
+
+
+ s = 1;
+ if ( a < 0 ) { a = -a; s = -1; }
+ if ( b < 0 ) { b = -b; s = -s; }
+ if ( c < 0 ) { c = -c; s = -s; }
+
+ d = (FT_Long)( c > 0 ? (FT_Int64)a * b / c
+ : 0x7FFFFFFFL );
+
+ return ( s > 0 ) ? d : -d;
+ }
+
+#endif /* TT_USE_BYTECODE_INTERPRETER */
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Long )
+ FT_MulFix( FT_Long a,
+ FT_Long b )
+ {
+#ifdef FT_MULFIX_ASSEMBLER
+
+ return FT_MULFIX_ASSEMBLER( a, b );
+
+#else
+
+ FT_Int s = 1;
+ FT_Long c;
+
+
+ if ( a < 0 )
+ {
+ a = -a;
+ s = -1;
+ }
+
+ if ( b < 0 )
+ {
+ b = -b;
+ s = -s;
+ }
+
+ c = (FT_Long)( ( (FT_Int64)a * b + 0x8000L ) >> 16 );
+
+ return ( s > 0 ) ? c : -c;
+
+#endif /* FT_MULFIX_ASSEMBLER */
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Long )
+ FT_DivFix( FT_Long a,
+ FT_Long b )
+ {
+ FT_Int32 s;
+ FT_UInt32 q;
+
+ s = 1;
+ if ( a < 0 ) { a = -a; s = -1; }
+ if ( b < 0 ) { b = -b; s = -s; }
+
+ if ( b == 0 )
+ /* check for division by 0 */
+ q = 0x7FFFFFFFL;
+ else
+ /* compute result directly */
+ q = (FT_UInt32)( ( ( (FT_Int64)a << 16 ) + ( b >> 1 ) ) / b );
+
+ return ( s < 0 ? -(FT_Long)q : (FT_Long)q );
+ }
+
+
+#else /* !FT_LONG64 */
+
+
+ static void
+ ft_multo64( FT_UInt32 x,
+ FT_UInt32 y,
+ FT_Int64 *z )
+ {
+ FT_UInt32 lo1, hi1, lo2, hi2, lo, hi, i1, i2;
+
+
+ lo1 = x & 0x0000FFFFU; hi1 = x >> 16;
+ lo2 = y & 0x0000FFFFU; hi2 = y >> 16;
+
+ lo = lo1 * lo2;
+ i1 = lo1 * hi2;
+ i2 = lo2 * hi1;
+ hi = hi1 * hi2;
+
+ /* Check carry overflow of i1 + i2 */
+ i1 += i2;
+ hi += (FT_UInt32)( i1 < i2 ) << 16;
+
+ hi += i1 >> 16;
+ i1 = i1 << 16;
+
+ /* Check carry overflow of i1 + lo */
+ lo += i1;
+ hi += ( lo < i1 );
+
+ z->lo = lo;
+ z->hi = hi;
+ }
+
+
+ static FT_UInt32
+ ft_div64by32( FT_UInt32 hi,
+ FT_UInt32 lo,
+ FT_UInt32 y )
+ {
+ FT_UInt32 r, q;
+ FT_Int i;
+
+
+ q = 0;
+ r = hi;
+
+ if ( r >= y )
+ return (FT_UInt32)0x7FFFFFFFL;
+
+ i = 32;
+ do
+ {
+ r <<= 1;
+ q <<= 1;
+ r |= lo >> 31;
+
+ if ( r >= (FT_UInt32)y )
+ {
+ r -= y;
+ q |= 1;
+ }
+ lo <<= 1;
+ } while ( --i );
+
+ return q;
+ }
+
+
+ static void
+ FT_Add64( FT_Int64* x,
+ FT_Int64* y,
+ FT_Int64 *z )
+ {
+ register FT_UInt32 lo, hi;
+
+
+ lo = x->lo + y->lo;
+ hi = x->hi + y->hi + ( lo < x->lo );
+
+ z->lo = lo;
+ z->hi = hi;
+ }
+
+
+ /* documentation is in freetype.h */
+
+ /* The FT_MulDiv function has been optimized thanks to ideas from */
+ /* Graham Asher. The trick is to optimize computation when everything */
+ /* fits within 32-bits (a rather common case). */
+ /* */
+ /* we compute 'a*b+c/2', then divide it by 'c'. (positive values) */
+ /* */
+ /* 46340 is FLOOR(SQRT(2^31-1)). */
+ /* */
+ /* if ( a <= 46340 && b <= 46340 ) then ( a*b <= 0x7FFEA810 ) */
+ /* */
+ /* 0x7FFFFFFF - 0x7FFEA810 = 0x157F0 */
+ /* */
+ /* if ( c < 0x157F0*2 ) then ( a*b+c/2 <= 0x7FFFFFFF ) */
+ /* */
+ /* and 2*0x157F0 = 176096 */
+ /* */
+
+ FT_EXPORT_DEF( FT_Long )
+ FT_MulDiv( FT_Long a,
+ FT_Long b,
+ FT_Long c )
+ {
+ long s;
+
+
+ if ( a == 0 || b == c )
+ return a;
+
+ s = a; a = FT_ABS( a );
+ s ^= b; b = FT_ABS( b );
+ s ^= c; c = FT_ABS( c );
+
+ if ( a <= 46340L && b <= 46340L && c <= 176095L && c > 0 )
+ a = ( a * b + ( c >> 1 ) ) / c;
+
+ else if ( c > 0 )
+ {
+ FT_Int64 temp, temp2;
+
+
+ ft_multo64( a, b, &temp );
+
+ temp2.hi = 0;
+ temp2.lo = (FT_UInt32)(c >> 1);
+ FT_Add64( &temp, &temp2, &temp );
+ a = ft_div64by32( temp.hi, temp.lo, c );
+ }
+ else
+ a = 0x7FFFFFFFL;
+
+ return ( s < 0 ? -a : a );
+ }
+
+
+#ifdef TT_USE_BYTECODE_INTERPRETER
+
+ FT_BASE_DEF( FT_Long )
+ FT_MulDiv_No_Round( FT_Long a,
+ FT_Long b,
+ FT_Long c )
+ {
+ long s;
+
+
+ if ( a == 0 || b == c )
+ return a;
+
+ s = a; a = FT_ABS( a );
+ s ^= b; b = FT_ABS( b );
+ s ^= c; c = FT_ABS( c );
+
+ if ( a <= 46340L && b <= 46340L && c > 0 )
+ a = a * b / c;
+
+ else if ( c > 0 )
+ {
+ FT_Int64 temp;
+
+
+ ft_multo64( a, b, &temp );
+ a = ft_div64by32( temp.hi, temp.lo, c );
+ }
+ else
+ a = 0x7FFFFFFFL;
+
+ return ( s < 0 ? -a : a );
+ }
+
+#endif /* TT_USE_BYTECODE_INTERPRETER */
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Long )
+ FT_MulFix( FT_Long a,
+ FT_Long b )
+ {
+#ifdef FT_MULFIX_ASSEMBLER
+
+ return FT_MULFIX_ASSEMBLER( a, b );
+
+#elif 0
+
+ /*
+ * This code is nonportable. See comment below.
+ *
+ * However, on a platform where right-shift of a signed quantity fills
+ * the leftmost bits by copying the sign bit, it might be faster.
+ */
+
+ FT_Long sa, sb;
+ FT_ULong ua, ub;
+
+
+ if ( a == 0 || b == 0x10000L )
+ return a;
+
+ /*
+ * This is a clever way of converting a signed number `a' into its
+ * absolute value (stored back into `a') and its sign. The sign is
+ * stored in `sa'; 0 means `a' was positive or zero, and -1 means `a'
+ * was negative. (Similarly for `b' and `sb').
+ *
+ * Unfortunately, it doesn't work (at least not portably).
+ *
+ * It makes the assumption that right-shift on a negative signed value
+ * fills the leftmost bits by copying the sign bit. This is wrong.
+ * According to K&R 2nd ed, section `A7.8 Shift Operators' on page 206,
+ * the result of right-shift of a negative signed value is
+ * implementation-defined. At least one implementation fills the
+ * leftmost bits with 0s (i.e., it is exactly the same as an unsigned
+ * right shift). This means that when `a' is negative, `sa' ends up
+ * with the value 1 rather than -1. After that, everything else goes
+ * wrong.
+ */
+ sa = ( a >> ( sizeof ( a ) * 8 - 1 ) );
+ a = ( a ^ sa ) - sa;
+ sb = ( b >> ( sizeof ( b ) * 8 - 1 ) );
+ b = ( b ^ sb ) - sb;
+
+ ua = (FT_ULong)a;
+ ub = (FT_ULong)b;
+
+ if ( ua <= 2048 && ub <= 1048576L )
+ ua = ( ua * ub + 0x8000U ) >> 16;
+ else
+ {
+ FT_ULong al = ua & 0xFFFFU;
+
+
+ ua = ( ua >> 16 ) * ub + al * ( ub >> 16 ) +
+ ( ( al * ( ub & 0xFFFFU ) + 0x8000U ) >> 16 );
+ }
+
+ sa ^= sb,
+ ua = (FT_ULong)(( ua ^ sa ) - sa);
+
+ return (FT_Long)ua;
+
+#else /* 0 */
+
+ FT_Long s;
+ FT_ULong ua, ub;
+
+
+ if ( a == 0 || b == 0x10000L )
+ return a;
+
+ s = a; a = FT_ABS( a );
+ s ^= b; b = FT_ABS( b );
+
+ ua = (FT_ULong)a;
+ ub = (FT_ULong)b;
+
+ if ( ua <= 2048 && ub <= 1048576L )
+ ua = ( ua * ub + 0x8000UL ) >> 16;
+ else
+ {
+ FT_ULong al = ua & 0xFFFFUL;
+
+
+ ua = ( ua >> 16 ) * ub + al * ( ub >> 16 ) +
+ ( ( al * ( ub & 0xFFFFUL ) + 0x8000UL ) >> 16 );
+ }
+
+ return ( s < 0 ? -(FT_Long)ua : (FT_Long)ua );
+
+#endif /* 0 */
+
+ }
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_Long )
+ FT_DivFix( FT_Long a,
+ FT_Long b )
+ {
+ FT_Int32 s;
+ FT_UInt32 q;
+
+
+ s = a; a = FT_ABS( a );
+ s ^= b; b = FT_ABS( b );
+
+ if ( b == 0 )
+ {
+ /* check for division by 0 */
+ q = 0x7FFFFFFFL;
+ }
+ else if ( ( a >> 16 ) == 0 )
+ {
+ /* compute result directly */
+ q = (FT_UInt32)( (a << 16) + (b >> 1) ) / (FT_UInt32)b;
+ }
+ else
+ {
+ /* we need more bits; we have to do it by hand */
+ FT_Int64 temp, temp2;
+
+ temp.hi = (FT_Int32) (a >> 16);
+ temp.lo = (FT_UInt32)(a << 16);
+ temp2.hi = 0;
+ temp2.lo = (FT_UInt32)( b >> 1 );
+ FT_Add64( &temp, &temp2, &temp );
+ q = ft_div64by32( temp.hi, temp.lo, b );
+ }
+
+ return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q );
+ }
+
+
+#if 0
+
+ /* documentation is in ftcalc.h */
+
+ FT_EXPORT_DEF( void )
+ FT_MulTo64( FT_Int32 x,
+ FT_Int32 y,
+ FT_Int64 *z )
+ {
+ FT_Int32 s;
+
+
+ s = x; x = FT_ABS( x );
+ s ^= y; y = FT_ABS( y );
+
+ ft_multo64( x, y, z );
+
+ if ( s < 0 )
+ {
+ z->lo = (FT_UInt32)-(FT_Int32)z->lo;
+ z->hi = ~z->hi + !( z->lo );
+ }
+ }
+
+
+ /* apparently, the second version of this code is not compiled correctly */
+ /* on Mac machines with the MPW C compiler.. tsk, tsk, tsk... */
+
+#if 1
+
+ FT_EXPORT_DEF( FT_Int32 )
+ FT_Div64by32( FT_Int64* x,
+ FT_Int32 y )
+ {
+ FT_Int32 s;
+ FT_UInt32 q, r, i, lo;
+
+
+ s = x->hi;
+ if ( s < 0 )
+ {
+ x->lo = (FT_UInt32)-(FT_Int32)x->lo;
+ x->hi = ~x->hi + !x->lo;
+ }
+ s ^= y; y = FT_ABS( y );
+
+ /* Shortcut */
+ if ( x->hi == 0 )
+ {
+ if ( y > 0 )
+ q = x->lo / y;
+ else
+ q = 0x7FFFFFFFL;
+
+ return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q );
+ }
+
+ r = x->hi;
+ lo = x->lo;
+
+ if ( r >= (FT_UInt32)y ) /* we know y is to be treated as unsigned here */
+ return ( s < 0 ? 0x80000001UL : 0x7FFFFFFFUL );
+ /* Return Max/Min Int32 if division overflow. */
+ /* This includes division by zero! */
+ q = 0;
+ for ( i = 0; i < 32; i++ )
+ {
+ r <<= 1;
+ q <<= 1;
+ r |= lo >> 31;
+
+ if ( r >= (FT_UInt32)y )
+ {
+ r -= y;
+ q |= 1;
+ }
+ lo <<= 1;
+ }
+
+ return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q );
+ }
+
+#else /* 0 */
+
+ FT_EXPORT_DEF( FT_Int32 )
+ FT_Div64by32( FT_Int64* x,
+ FT_Int32 y )
+ {
+ FT_Int32 s;
+ FT_UInt32 q;
+
+
+ s = x->hi;
+ if ( s < 0 )
+ {
+ x->lo = (FT_UInt32)-(FT_Int32)x->lo;
+ x->hi = ~x->hi + !x->lo;
+ }
+ s ^= y; y = FT_ABS( y );
+
+ /* Shortcut */
+ if ( x->hi == 0 )
+ {
+ if ( y > 0 )
+ q = ( x->lo + ( y >> 1 ) ) / y;
+ else
+ q = 0x7FFFFFFFL;
+
+ return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q );
+ }
+
+ q = ft_div64by32( x->hi, x->lo, y );
+
+ return ( s < 0 ? -(FT_Int32)q : (FT_Int32)q );
+ }
+
+#endif /* 0 */
+
+#endif /* 0 */
+
+
+#endif /* FT_LONG64 */
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Matrix_Multiply( const FT_Matrix* a,
+ FT_Matrix *b )
+ {
+ FT_Fixed xx, xy, yx, yy;
+
+
+ if ( !a || !b )
+ return;
+
+ xx = FT_MulFix( a->xx, b->xx ) + FT_MulFix( a->xy, b->yx );
+ xy = FT_MulFix( a->xx, b->xy ) + FT_MulFix( a->xy, b->yy );
+ yx = FT_MulFix( a->yx, b->xx ) + FT_MulFix( a->yy, b->yx );
+ yy = FT_MulFix( a->yx, b->xy ) + FT_MulFix( a->yy, b->yy );
+
+ b->xx = xx; b->xy = xy;
+ b->yx = yx; b->yy = yy;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Matrix_Invert( FT_Matrix* matrix )
+ {
+ FT_Pos delta, xx, yy;
+
+
+ if ( !matrix )
+ return FT_Err_Invalid_Argument;
+
+ /* compute discriminant */
+ delta = FT_MulFix( matrix->xx, matrix->yy ) -
+ FT_MulFix( matrix->xy, matrix->yx );
+
+ if ( !delta )
+ return FT_Err_Invalid_Argument; /* matrix can't be inverted */
+
+ matrix->xy = - FT_DivFix( matrix->xy, delta );
+ matrix->yx = - FT_DivFix( matrix->yx, delta );
+
+ xx = matrix->xx;
+ yy = matrix->yy;
+
+ matrix->xx = FT_DivFix( yy, delta );
+ matrix->yy = FT_DivFix( xx, delta );
+
+ return FT_Err_Ok;
+ }
+
+
+ /* documentation is in ftcalc.h */
+
+ FT_BASE_DEF( void )
+ FT_Matrix_Multiply_Scaled( const FT_Matrix* a,
+ FT_Matrix *b,
+ FT_Long scaling )
+ {
+ FT_Fixed xx, xy, yx, yy;
+
+ FT_Long val = 0x10000L * scaling;
+
+
+ if ( !a || !b )
+ return;
+
+ xx = FT_MulDiv( a->xx, b->xx, val ) + FT_MulDiv( a->xy, b->yx, val );
+ xy = FT_MulDiv( a->xx, b->xy, val ) + FT_MulDiv( a->xy, b->yy, val );
+ yx = FT_MulDiv( a->yx, b->xx, val ) + FT_MulDiv( a->yy, b->yx, val );
+ yy = FT_MulDiv( a->yx, b->xy, val ) + FT_MulDiv( a->yy, b->yy, val );
+
+ b->xx = xx; b->xy = xy;
+ b->yx = yx; b->yy = yy;
+ }
+
+
+ /* documentation is in ftcalc.h */
+
+ FT_BASE_DEF( void )
+ FT_Vector_Transform_Scaled( FT_Vector* vector,
+ const FT_Matrix* matrix,
+ FT_Long scaling )
+ {
+ FT_Pos xz, yz;
+
+ FT_Long val = 0x10000L * scaling;
+
+
+ if ( !vector || !matrix )
+ return;
+
+ xz = FT_MulDiv( vector->x, matrix->xx, val ) +
+ FT_MulDiv( vector->y, matrix->xy, val );
+
+ yz = FT_MulDiv( vector->x, matrix->yx, val ) +
+ FT_MulDiv( vector->y, matrix->yy, val );
+
+ vector->x = xz;
+ vector->y = yz;
+ }
+
+
+ /* documentation is in ftcalc.h */
+
+ FT_BASE_DEF( FT_Int32 )
+ FT_SqrtFixed( FT_Int32 x )
+ {
+ FT_UInt32 root, rem_hi, rem_lo, test_div;
+ FT_Int count;
+
+
+ root = 0;
+
+ if ( x > 0 )
+ {
+ rem_hi = 0;
+ rem_lo = x;
+ count = 24;
+ do
+ {
+ rem_hi = ( rem_hi << 2 ) | ( rem_lo >> 30 );
+ rem_lo <<= 2;
+ root <<= 1;
+ test_div = ( root << 1 ) + 1;
+
+ if ( rem_hi >= test_div )
+ {
+ rem_hi -= test_div;
+ root += 1;
+ }
+ } while ( --count );
+ }
+
+ return (FT_Int32)root;
+ }
+
+
+ /* documentation is in ftcalc.h */
+
+ FT_BASE_DEF( FT_Int )
+ ft_corner_orientation( FT_Pos in_x,
+ FT_Pos in_y,
+ FT_Pos out_x,
+ FT_Pos out_y )
+ {
+ FT_Int result;
+
+
+ /* deal with the trivial cases quickly */
+ if ( in_y == 0 )
+ {
+ if ( in_x >= 0 )
+ result = out_y;
+ else
+ result = -out_y;
+ }
+ else if ( in_x == 0 )
+ {
+ if ( in_y >= 0 )
+ result = -out_x;
+ else
+ result = out_x;
+ }
+ else if ( out_y == 0 )
+ {
+ if ( out_x >= 0 )
+ result = in_y;
+ else
+ result = -in_y;
+ }
+ else if ( out_x == 0 )
+ {
+ if ( out_y >= 0 )
+ result = -in_x;
+ else
+ result = in_x;
+ }
+ else /* general case */
+ {
+#ifdef FT_LONG64
+
+ FT_Int64 delta = (FT_Int64)in_x * out_y - (FT_Int64)in_y * out_x;
+
+
+ if ( delta == 0 )
+ result = 0;
+ else
+ result = 1 - 2 * ( delta < 0 );
+
+#else
+
+ FT_Int64 z1, z2;
+
+
+ ft_multo64( in_x, out_y, &z1 );
+ ft_multo64( in_y, out_x, &z2 );
+
+ if ( z1.hi > z2.hi )
+ result = +1;
+ else if ( z1.hi < z2.hi )
+ result = -1;
+ else if ( z1.lo > z2.lo )
+ result = +1;
+ else if ( z1.lo < z2.lo )
+ result = -1;
+ else
+ result = 0;
+
+#endif
+ }
+
+ return result;
+ }
+
+
+ /* documentation is in ftcalc.h */
+
+ FT_BASE_DEF( FT_Int )
+ ft_corner_is_flat( FT_Pos in_x,
+ FT_Pos in_y,
+ FT_Pos out_x,
+ FT_Pos out_y )
+ {
+ FT_Pos ax = in_x;
+ FT_Pos ay = in_y;
+
+ FT_Pos d_in, d_out, d_corner;
+
+
+ if ( ax < 0 )
+ ax = -ax;
+ if ( ay < 0 )
+ ay = -ay;
+ d_in = ax + ay;
+
+ ax = out_x;
+ if ( ax < 0 )
+ ax = -ax;
+ ay = out_y;
+ if ( ay < 0 )
+ ay = -ay;
+ d_out = ax + ay;
+
+ ax = out_x + in_x;
+ if ( ax < 0 )
+ ax = -ax;
+ ay = out_y + in_y;
+ if ( ay < 0 )
+ ay = -ay;
+ d_corner = ax + ay;
+
+ return ( d_in + d_out - d_corner ) < ( d_corner >> 4 );
+ }
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/base/ftcid.c b/src/3rdparty/freetype/src/base/ftcid.c
new file mode 100644
index 0000000000..733aae1475
--- /dev/null
+++ b/src/3rdparty/freetype/src/base/ftcid.c
@@ -0,0 +1,117 @@
+/***************************************************************************/
+/* */
+/* ftcid.c */
+/* */
+/* FreeType API for accessing CID font information. */
+/* */
+/* Copyright 2007, 2009 by Derek Clegg, Michael Toftdal. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CID_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_SERVICE_CID_H
+
+
+ /* documentation is in ftcid.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_CID_Registry_Ordering_Supplement( FT_Face face,
+ const char* *registry,
+ const char* *ordering,
+ FT_Int *supplement)
+ {
+ FT_Error error;
+ const char* r = NULL;
+ const char* o = NULL;
+ FT_Int s = 0;
+
+
+ error = FT_Err_Invalid_Argument;
+
+ if ( face )
+ {
+ FT_Service_CID service;
+
+
+ FT_FACE_FIND_SERVICE( face, service, CID );
+
+ if ( service && service->get_ros )
+ error = service->get_ros( face, &r, &o, &s );
+ }
+
+ if ( registry )
+ *registry = r;
+
+ if ( ordering )
+ *ordering = o;
+
+ if ( supplement )
+ *supplement = s;
+
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_CID_Is_Internally_CID_Keyed( FT_Face face,
+ FT_Bool *is_cid )
+ {
+ FT_Error error = FT_Err_Invalid_Argument;
+ FT_Bool ic = 0;
+
+
+ if ( face )
+ {
+ FT_Service_CID service;
+
+
+ FT_FACE_FIND_SERVICE( face, service, CID );
+
+ if ( service && service->get_is_cid )
+ error = service->get_is_cid( face, &ic);
+ }
+
+ if ( is_cid )
+ *is_cid = ic;
+
+ return error;
+ }
+
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_CID_From_Glyph_Index( FT_Face face,
+ FT_UInt glyph_index,
+ FT_UInt *cid )
+ {
+ FT_Error error = FT_Err_Invalid_Argument;
+ FT_UInt c = 0;
+
+
+ if ( face )
+ {
+ FT_Service_CID service;
+
+
+ FT_FACE_FIND_SERVICE( face, service, CID );
+
+ if ( service && service->get_cid_from_glyph_index )
+ error = service->get_cid_from_glyph_index( face, glyph_index, &c);
+ }
+
+ if ( cid )
+ *cid = c;
+
+ return error;
+ }
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/base/ftdbgmem.c b/src/3rdparty/freetype/src/base/ftdbgmem.c
new file mode 100644
index 0000000000..8b2a3304f0
--- /dev/null
+++ b/src/3rdparty/freetype/src/base/ftdbgmem.c
@@ -0,0 +1,997 @@
+/***************************************************************************/
+/* */
+/* ftdbgmem.c */
+/* */
+/* Memory debugger (body). */
+/* */
+/* Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2009 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_MEMORY_H
+#include FT_SYSTEM_H
+#include FT_ERRORS_H
+#include FT_TYPES_H
+
+
+#ifdef FT_DEBUG_MEMORY
+
+#define KEEPALIVE /* `Keep alive' means that freed blocks aren't released
+ * to the heap. This is useful to detect double-frees
+ * or weird heap corruption, but it uses large amounts of
+ * memory, however.
+ */
+
+#include FT_CONFIG_STANDARD_LIBRARY_H
+
+ FT_BASE_DEF( const char* ) _ft_debug_file = 0;
+ FT_BASE_DEF( long ) _ft_debug_lineno = 0;
+
+ extern void
+ FT_DumpMemory( FT_Memory memory );
+
+
+ typedef struct FT_MemSourceRec_* FT_MemSource;
+ typedef struct FT_MemNodeRec_* FT_MemNode;
+ typedef struct FT_MemTableRec_* FT_MemTable;
+
+
+#define FT_MEM_VAL( addr ) ((FT_ULong)(FT_Pointer)( addr ))
+
+ /*
+ * This structure holds statistics for a single allocation/release
+ * site. This is useful to know where memory operations happen the
+ * most.
+ */
+ typedef struct FT_MemSourceRec_
+ {
+ const char* file_name;
+ long line_no;
+
+ FT_Long cur_blocks; /* current number of allocated blocks */
+ FT_Long max_blocks; /* max. number of allocated blocks */
+ FT_Long all_blocks; /* total number of blocks allocated */
+
+ FT_Long cur_size; /* current cumulative allocated size */
+ FT_Long max_size; /* maximum cumulative allocated size */
+ FT_Long all_size; /* total cumulative allocated size */
+
+ FT_Long cur_max; /* current maximum allocated size */
+
+ FT_UInt32 hash;
+ FT_MemSource link;
+
+ } FT_MemSourceRec;
+
+
+ /*
+ * We don't need a resizable array for the memory sources, because
+ * their number is pretty limited within FreeType.
+ */
+#define FT_MEM_SOURCE_BUCKETS 128
+
+ /*
+ * This structure holds information related to a single allocated
+ * memory block. If KEEPALIVE is defined, blocks that are freed by
+ * FreeType are never released to the system. Instead, their `size'
+ * field is set to -size. This is mainly useful to detect double frees,
+ * at the price of large memory footprint during execution.
+ */
+ typedef struct FT_MemNodeRec_
+ {
+ FT_Byte* address;
+ FT_Long size; /* < 0 if the block was freed */
+
+ FT_MemSource source;
+
+#ifdef KEEPALIVE
+ const char* free_file_name;
+ FT_Long free_line_no;
+#endif
+
+ FT_MemNode link;
+
+ } FT_MemNodeRec;
+
+
+ /*
+ * The global structure, containing compound statistics and all hash
+ * tables.
+ */
+ typedef struct FT_MemTableRec_
+ {
+ FT_ULong size;
+ FT_ULong nodes;
+ FT_MemNode* buckets;
+
+ FT_ULong alloc_total;
+ FT_ULong alloc_current;
+ FT_ULong alloc_max;
+ FT_ULong alloc_count;
+
+ FT_Bool bound_total;
+ FT_ULong alloc_total_max;
+
+ FT_Bool bound_count;
+ FT_ULong alloc_count_max;
+
+ FT_MemSource sources[FT_MEM_SOURCE_BUCKETS];
+
+ FT_Bool keep_alive;
+
+ FT_Memory memory;
+ FT_Pointer memory_user;
+ FT_Alloc_Func alloc;
+ FT_Free_Func free;
+ FT_Realloc_Func realloc;
+
+ } FT_MemTableRec;
+
+
+#define FT_MEM_SIZE_MIN 7
+#define FT_MEM_SIZE_MAX 13845163
+
+#define FT_FILENAME( x ) ((x) ? (x) : "unknown file")
+
+
+ /*
+ * Prime numbers are ugly to handle. It would be better to implement
+ * L-Hashing, which is 10% faster and doesn't require divisions.
+ */
+ static const FT_UInt ft_mem_primes[] =
+ {
+ 7,
+ 11,
+ 19,
+ 37,
+ 73,
+ 109,
+ 163,
+ 251,
+ 367,
+ 557,
+ 823,
+ 1237,
+ 1861,
+ 2777,
+ 4177,
+ 6247,
+ 9371,
+ 14057,
+ 21089,
+ 31627,
+ 47431,
+ 71143,
+ 106721,
+ 160073,
+ 240101,
+ 360163,
+ 540217,
+ 810343,
+ 1215497,
+ 1823231,
+ 2734867,
+ 4102283,
+ 6153409,
+ 9230113,
+ 13845163,
+ };
+
+
+ static FT_ULong
+ ft_mem_closest_prime( FT_ULong num )
+ {
+ FT_UInt i;
+
+
+ for ( i = 0;
+ i < sizeof ( ft_mem_primes ) / sizeof ( ft_mem_primes[0] ); i++ )
+ if ( ft_mem_primes[i] > num )
+ return ft_mem_primes[i];
+
+ return FT_MEM_SIZE_MAX;
+ }
+
+
+ extern void
+ ft_mem_debug_panic( const char* fmt,
+ ... )
+ {
+ va_list ap;
+
+
+ printf( "FreeType.Debug: " );
+
+ va_start( ap, fmt );
+ vprintf( fmt, ap );
+ va_end( ap );
+
+ printf( "\n" );
+ exit( EXIT_FAILURE );
+ }
+
+
+ static FT_Pointer
+ ft_mem_table_alloc( FT_MemTable table,
+ FT_Long size )
+ {
+ FT_Memory memory = table->memory;
+ FT_Pointer block;
+
+
+ memory->user = table->memory_user;
+ block = table->alloc( memory, size );
+ memory->user = table;
+
+ return block;
+ }
+
+
+ static void
+ ft_mem_table_free( FT_MemTable table,
+ FT_Pointer block )
+ {
+ FT_Memory memory = table->memory;
+
+
+ memory->user = table->memory_user;
+ table->free( memory, block );
+ memory->user = table;
+ }
+
+
+ static void
+ ft_mem_table_resize( FT_MemTable table )
+ {
+ FT_ULong new_size;
+
+
+ new_size = ft_mem_closest_prime( table->nodes );
+ if ( new_size != table->size )
+ {
+ FT_MemNode* new_buckets;
+ FT_ULong i;
+
+
+ new_buckets = (FT_MemNode *)
+ ft_mem_table_alloc( table,
+ new_size * sizeof ( FT_MemNode ) );
+ if ( new_buckets == NULL )
+ return;
+
+ FT_ARRAY_ZERO( new_buckets, new_size );
+
+ for ( i = 0; i < table->size; i++ )
+ {
+ FT_MemNode node, next, *pnode;
+ FT_ULong hash;
+
+
+ node = table->buckets[i];
+ while ( node )
+ {
+ next = node->link;
+ hash = FT_MEM_VAL( node->address ) % new_size;
+ pnode = new_buckets + hash;
+
+ node->link = pnode[0];
+ pnode[0] = node;
+
+ node = next;
+ }
+ }
+
+ if ( table->buckets )
+ ft_mem_table_free( table, table->buckets );
+
+ table->buckets = new_buckets;
+ table->size = new_size;
+ }
+ }
+
+
+ static FT_MemTable
+ ft_mem_table_new( FT_Memory memory )
+ {
+ FT_MemTable table;
+
+
+ table = (FT_MemTable)memory->alloc( memory, sizeof ( *table ) );
+ if ( table == NULL )
+ goto Exit;
+
+ FT_ZERO( table );
+
+ table->size = FT_MEM_SIZE_MIN;
+ table->nodes = 0;
+
+ table->memory = memory;
+
+ table->memory_user = memory->user;
+
+ table->alloc = memory->alloc;
+ table->realloc = memory->realloc;
+ table->free = memory->free;
+
+ table->buckets = (FT_MemNode *)
+ memory->alloc( memory,
+ table->size * sizeof ( FT_MemNode ) );
+ if ( table->buckets )
+ FT_ARRAY_ZERO( table->buckets, table->size );
+ else
+ {
+ memory->free( memory, table );
+ table = NULL;
+ }
+
+ Exit:
+ return table;
+ }
+
+
+ static void
+ ft_mem_table_destroy( FT_MemTable table )
+ {
+ FT_ULong i;
+
+
+ FT_DumpMemory( table->memory );
+
+ if ( table )
+ {
+ FT_Long leak_count = 0;
+ FT_ULong leaks = 0;
+
+
+ /* remove all blocks from the table, revealing leaked ones */
+ for ( i = 0; i < table->size; i++ )
+ {
+ FT_MemNode *pnode = table->buckets + i, next, node = *pnode;
+
+
+ while ( node )
+ {
+ next = node->link;
+ node->link = 0;
+
+ if ( node->size > 0 )
+ {
+ printf(
+ "leaked memory block at address %p, size %8ld in (%s:%ld)\n",
+ node->address, node->size,
+ FT_FILENAME( node->source->file_name ),
+ node->source->line_no );
+
+ leak_count++;
+ leaks += node->size;
+
+ ft_mem_table_free( table, node->address );
+ }
+
+ node->address = NULL;
+ node->size = 0;
+
+ ft_mem_table_free( table, node );
+ node = next;
+ }
+ table->buckets[i] = 0;
+ }
+
+ ft_mem_table_free( table, table->buckets );
+ table->buckets = NULL;
+
+ table->size = 0;
+ table->nodes = 0;
+
+ /* remove all sources */
+ for ( i = 0; i < FT_MEM_SOURCE_BUCKETS; i++ )
+ {
+ FT_MemSource source, next;
+
+
+ for ( source = table->sources[i]; source != NULL; source = next )
+ {
+ next = source->link;
+ ft_mem_table_free( table, source );
+ }
+
+ table->sources[i] = NULL;
+ }
+
+ printf(
+ "FreeType: total memory allocations = %ld\n", table->alloc_total );
+ printf(
+ "FreeType: maximum memory footprint = %ld\n", table->alloc_max );
+
+ ft_mem_table_free( table, table );
+
+ if ( leak_count > 0 )
+ ft_mem_debug_panic(
+ "FreeType: %ld bytes of memory leaked in %ld blocks\n",
+ leaks, leak_count );
+
+ printf( "FreeType: No memory leaks detected!\n" );
+ }
+ }
+
+
+ static FT_MemNode*
+ ft_mem_table_get_nodep( FT_MemTable table,
+ FT_Byte* address )
+ {
+ FT_ULong hash;
+ FT_MemNode *pnode, node;
+
+
+ hash = FT_MEM_VAL( address );
+ pnode = table->buckets + ( hash % table->size );
+
+ for (;;)
+ {
+ node = pnode[0];
+ if ( !node )
+ break;
+
+ if ( node->address == address )
+ break;
+
+ pnode = &node->link;
+ }
+ return pnode;
+ }
+
+
+ static FT_MemSource
+ ft_mem_table_get_source( FT_MemTable table )
+ {
+ FT_UInt32 hash;
+ FT_MemSource node, *pnode;
+
+
+ /* cast to FT_PtrDist first since void* can be larger */
+ /* than FT_UInt32 and GCC 4.1.1 emits a warning */
+ hash = (FT_UInt32)(FT_PtrDist)(void*)_ft_debug_file +
+ (FT_UInt32)( 5 * _ft_debug_lineno );
+ pnode = &table->sources[hash % FT_MEM_SOURCE_BUCKETS];
+
+ for ( ;; )
+ {
+ node = *pnode;
+ if ( node == NULL )
+ break;
+
+ if ( node->file_name == _ft_debug_file &&
+ node->line_no == _ft_debug_lineno )
+ goto Exit;
+
+ pnode = &node->link;
+ }
+
+ node = (FT_MemSource)ft_mem_table_alloc( table, sizeof ( *node ) );
+ if ( node == NULL )
+ ft_mem_debug_panic(
+ "not enough memory to perform memory debugging\n" );
+
+ node->file_name = _ft_debug_file;
+ node->line_no = _ft_debug_lineno;
+
+ node->cur_blocks = 0;
+ node->max_blocks = 0;
+ node->all_blocks = 0;
+
+ node->cur_size = 0;
+ node->max_size = 0;
+ node->all_size = 0;
+
+ node->cur_max = 0;
+
+ node->link = NULL;
+ node->hash = hash;
+ *pnode = node;
+
+ Exit:
+ return node;
+ }
+
+
+ static void
+ ft_mem_table_set( FT_MemTable table,
+ FT_Byte* address,
+ FT_ULong size,
+ FT_Long delta )
+ {
+ FT_MemNode *pnode, node;
+
+
+ if ( table )
+ {
+ FT_MemSource source;
+
+
+ pnode = ft_mem_table_get_nodep( table, address );
+ node = *pnode;
+ if ( node )
+ {
+ if ( node->size < 0 )
+ {
+ /* This block was already freed. Our memory is now completely */
+ /* corrupted! */
+ /* This can only happen in keep-alive mode. */
+ ft_mem_debug_panic(
+ "memory heap corrupted (allocating freed block)" );
+ }
+ else
+ {
+ /* This block was already allocated. This means that our memory */
+ /* is also corrupted! */
+ ft_mem_debug_panic(
+ "memory heap corrupted (re-allocating allocated block at"
+ " %p, of size %ld)\n"
+ "org=%s:%d new=%s:%d\n",
+ node->address, node->size,
+ FT_FILENAME( node->source->file_name ), node->source->line_no,
+ FT_FILENAME( _ft_debug_file ), _ft_debug_lineno );
+ }
+ }
+
+ /* we need to create a new node in this table */
+ node = (FT_MemNode)ft_mem_table_alloc( table, sizeof ( *node ) );
+ if ( node == NULL )
+ ft_mem_debug_panic( "not enough memory to run memory tests" );
+
+ node->address = address;
+ node->size = size;
+ node->source = source = ft_mem_table_get_source( table );
+
+ if ( delta == 0 )
+ {
+ /* this is an allocation */
+ source->all_blocks++;
+ source->cur_blocks++;
+ if ( source->cur_blocks > source->max_blocks )
+ source->max_blocks = source->cur_blocks;
+ }
+
+ if ( size > (FT_ULong)source->cur_max )
+ source->cur_max = size;
+
+ if ( delta != 0 )
+ {
+ /* we are growing or shrinking a reallocated block */
+ source->cur_size += delta;
+ table->alloc_current += delta;
+ }
+ else
+ {
+ /* we are allocating a new block */
+ source->cur_size += size;
+ table->alloc_current += size;
+ }
+
+ source->all_size += size;
+
+ if ( source->cur_size > source->max_size )
+ source->max_size = source->cur_size;
+
+ node->free_file_name = NULL;
+ node->free_line_no = 0;
+
+ node->link = pnode[0];
+
+ pnode[0] = node;
+ table->nodes++;
+
+ table->alloc_total += size;
+
+ if ( table->alloc_current > table->alloc_max )
+ table->alloc_max = table->alloc_current;
+
+ if ( table->nodes * 3 < table->size ||
+ table->size * 3 < table->nodes )
+ ft_mem_table_resize( table );
+ }
+ }
+
+
+ static void
+ ft_mem_table_remove( FT_MemTable table,
+ FT_Byte* address,
+ FT_Long delta )
+ {
+ if ( table )
+ {
+ FT_MemNode *pnode, node;
+
+
+ pnode = ft_mem_table_get_nodep( table, address );
+ node = *pnode;
+ if ( node )
+ {
+ FT_MemSource source;
+
+
+ if ( node->size < 0 )
+ ft_mem_debug_panic(
+ "freeing memory block at %p more than once at (%s:%ld)\n"
+ "block allocated at (%s:%ld) and released at (%s:%ld)",
+ address,
+ FT_FILENAME( _ft_debug_file ), _ft_debug_lineno,
+ FT_FILENAME( node->source->file_name ), node->source->line_no,
+ FT_FILENAME( node->free_file_name ), node->free_line_no );
+
+ /* scramble the node's content for additional safety */
+ FT_MEM_SET( address, 0xF3, node->size );
+
+ if ( delta == 0 )
+ {
+ source = node->source;
+
+ source->cur_blocks--;
+ source->cur_size -= node->size;
+
+ table->alloc_current -= node->size;
+ }
+
+ if ( table->keep_alive )
+ {
+ /* we simply invert the node's size to indicate that the node */
+ /* was freed. */
+ node->size = -node->size;
+ node->free_file_name = _ft_debug_file;
+ node->free_line_no = _ft_debug_lineno;
+ }
+ else
+ {
+ table->nodes--;
+
+ *pnode = node->link;
+
+ node->size = 0;
+ node->source = NULL;
+
+ ft_mem_table_free( table, node );
+
+ if ( table->nodes * 3 < table->size ||
+ table->size * 3 < table->nodes )
+ ft_mem_table_resize( table );
+ }
+ }
+ else
+ ft_mem_debug_panic(
+ "trying to free unknown block at %p in (%s:%ld)\n",
+ address,
+ FT_FILENAME( _ft_debug_file ), _ft_debug_lineno );
+ }
+ }
+
+
+ extern FT_Pointer
+ ft_mem_debug_alloc( FT_Memory memory,
+ FT_Long size )
+ {
+ FT_MemTable table = (FT_MemTable)memory->user;
+ FT_Byte* block;
+
+
+ if ( size <= 0 )
+ ft_mem_debug_panic( "negative block size allocation (%ld)", size );
+
+ /* return NULL if the maximum number of allocations was reached */
+ if ( table->bound_count &&
+ table->alloc_count >= table->alloc_count_max )
+ return NULL;
+
+ /* return NULL if this allocation would overflow the maximum heap size */
+ if ( table->bound_total &&
+ table->alloc_total_max - table->alloc_current > (FT_ULong)size )
+ return NULL;
+
+ block = (FT_Byte *)ft_mem_table_alloc( table, size );
+ if ( block )
+ {
+ ft_mem_table_set( table, block, (FT_ULong)size, 0 );
+
+ table->alloc_count++;
+ }
+
+ _ft_debug_file = "<unknown>";
+ _ft_debug_lineno = 0;
+
+ return (FT_Pointer)block;
+ }
+
+
+ extern void
+ ft_mem_debug_free( FT_Memory memory,
+ FT_Pointer block )
+ {
+ FT_MemTable table = (FT_MemTable)memory->user;
+
+
+ if ( block == NULL )
+ ft_mem_debug_panic( "trying to free NULL in (%s:%ld)",
+ FT_FILENAME( _ft_debug_file ),
+ _ft_debug_lineno );
+
+ ft_mem_table_remove( table, (FT_Byte*)block, 0 );
+
+ if ( !table->keep_alive )
+ ft_mem_table_free( table, block );
+
+ table->alloc_count--;
+
+ _ft_debug_file = "<unknown>";
+ _ft_debug_lineno = 0;
+ }
+
+
+ extern FT_Pointer
+ ft_mem_debug_realloc( FT_Memory memory,
+ FT_Long cur_size,
+ FT_Long new_size,
+ FT_Pointer block )
+ {
+ FT_MemTable table = (FT_MemTable)memory->user;
+ FT_MemNode node, *pnode;
+ FT_Pointer new_block;
+ FT_Long delta;
+
+ const char* file_name = FT_FILENAME( _ft_debug_file );
+ FT_Long line_no = _ft_debug_lineno;
+
+
+ /* unlikely, but possible */
+ if ( new_size == cur_size )
+ return block;
+
+ /* the following is valid according to ANSI C */
+#if 0
+ if ( block == NULL || cur_size == 0 )
+ ft_mem_debug_panic( "trying to reallocate NULL in (%s:%ld)",
+ file_name, line_no );
+#endif
+
+ /* while the following is allowed in ANSI C also, we abort since */
+ /* such case should be handled by FreeType. */
+ if ( new_size <= 0 )
+ ft_mem_debug_panic(
+ "trying to reallocate %p to size 0 (current is %ld) in (%s:%ld)",
+ block, cur_size, file_name, line_no );
+
+ /* check `cur_size' value */
+ pnode = ft_mem_table_get_nodep( table, (FT_Byte*)block );
+ node = *pnode;
+ if ( !node )
+ ft_mem_debug_panic(
+ "trying to reallocate unknown block at %p in (%s:%ld)",
+ block, file_name, line_no );
+
+ if ( node->size <= 0 )
+ ft_mem_debug_panic(
+ "trying to reallocate freed block at %p in (%s:%ld)",
+ block, file_name, line_no );
+
+ if ( node->size != cur_size )
+ ft_mem_debug_panic( "invalid ft_realloc request for %p. cur_size is "
+ "%ld instead of %ld in (%s:%ld)",
+ block, cur_size, node->size, file_name, line_no );
+
+ /* return NULL if the maximum number of allocations was reached */
+ if ( table->bound_count &&
+ table->alloc_count >= table->alloc_count_max )
+ return NULL;
+
+ delta = (FT_Long)( new_size - cur_size );
+
+ /* return NULL if this allocation would overflow the maximum heap size */
+ if ( delta > 0 &&
+ table->bound_total &&
+ table->alloc_current + (FT_ULong)delta > table->alloc_total_max )
+ return NULL;
+
+ new_block = (FT_Byte *)ft_mem_table_alloc( table, new_size );
+ if ( new_block == NULL )
+ return NULL;
+
+ ft_mem_table_set( table, (FT_Byte*)new_block, new_size, delta );
+
+ ft_memcpy( new_block, block, cur_size < new_size ? cur_size : new_size );
+
+ ft_mem_table_remove( table, (FT_Byte*)block, delta );
+
+ _ft_debug_file = "<unknown>";
+ _ft_debug_lineno = 0;
+
+ if ( !table->keep_alive )
+ ft_mem_table_free( table, block );
+
+ return new_block;
+ }
+
+
+ extern FT_Int
+ ft_mem_debug_init( FT_Memory memory )
+ {
+ FT_MemTable table;
+ FT_Int result = 0;
+
+
+ if ( getenv( "FT2_DEBUG_MEMORY" ) )
+ {
+ table = ft_mem_table_new( memory );
+ if ( table )
+ {
+ const char* p;
+
+
+ memory->user = table;
+ memory->alloc = ft_mem_debug_alloc;
+ memory->realloc = ft_mem_debug_realloc;
+ memory->free = ft_mem_debug_free;
+
+ p = getenv( "FT2_ALLOC_TOTAL_MAX" );
+ if ( p != NULL )
+ {
+ FT_Long total_max = ft_atol( p );
+
+
+ if ( total_max > 0 )
+ {
+ table->bound_total = 1;
+ table->alloc_total_max = (FT_ULong)total_max;
+ }
+ }
+
+ p = getenv( "FT2_ALLOC_COUNT_MAX" );
+ if ( p != NULL )
+ {
+ FT_Long total_count = ft_atol( p );
+
+
+ if ( total_count > 0 )
+ {
+ table->bound_count = 1;
+ table->alloc_count_max = (FT_ULong)total_count;
+ }
+ }
+
+ p = getenv( "FT2_KEEP_ALIVE" );
+ if ( p != NULL )
+ {
+ FT_Long keep_alive = ft_atol( p );
+
+
+ if ( keep_alive > 0 )
+ table->keep_alive = 1;
+ }
+
+ result = 1;
+ }
+ }
+ return result;
+ }
+
+
+ extern void
+ ft_mem_debug_done( FT_Memory memory )
+ {
+ FT_MemTable table = (FT_MemTable)memory->user;
+
+
+ if ( table )
+ {
+ memory->free = table->free;
+ memory->realloc = table->realloc;
+ memory->alloc = table->alloc;
+
+ ft_mem_table_destroy( table );
+ memory->user = NULL;
+ }
+ }
+
+
+
+ static int
+ ft_mem_source_compare( const void* p1,
+ const void* p2 )
+ {
+ FT_MemSource s1 = *(FT_MemSource*)p1;
+ FT_MemSource s2 = *(FT_MemSource*)p2;
+
+
+ if ( s2->max_size > s1->max_size )
+ return 1;
+ else if ( s2->max_size < s1->max_size )
+ return -1;
+ else
+ return 0;
+ }
+
+
+ extern void
+ FT_DumpMemory( FT_Memory memory )
+ {
+ FT_MemTable table = (FT_MemTable)memory->user;
+
+
+ if ( table )
+ {
+ FT_MemSource* bucket = table->sources;
+ FT_MemSource* limit = bucket + FT_MEM_SOURCE_BUCKETS;
+ FT_MemSource* sources;
+ FT_UInt nn, count;
+ const char* fmt;
+
+
+ count = 0;
+ for ( ; bucket < limit; bucket++ )
+ {
+ FT_MemSource source = *bucket;
+
+
+ for ( ; source; source = source->link )
+ count++;
+ }
+
+ sources = (FT_MemSource*)ft_mem_table_alloc(
+ table, sizeof ( *sources ) * count );
+
+ count = 0;
+ for ( bucket = table->sources; bucket < limit; bucket++ )
+ {
+ FT_MemSource source = *bucket;
+
+
+ for ( ; source; source = source->link )
+ sources[count++] = source;
+ }
+
+ ft_qsort( sources, count, sizeof ( *sources ), ft_mem_source_compare );
+
+ printf( "FreeType Memory Dump: "
+ "current=%ld max=%ld total=%ld count=%ld\n",
+ table->alloc_current, table->alloc_max,
+ table->alloc_total, table->alloc_count );
+ printf( " block block sizes sizes sizes source\n" );
+ printf( " count high sum highsum max location\n" );
+ printf( "-------------------------------------------------\n" );
+
+ fmt = "%6ld %6ld %8ld %8ld %8ld %s:%d\n";
+
+ for ( nn = 0; nn < count; nn++ )
+ {
+ FT_MemSource source = sources[nn];
+
+
+ printf( fmt,
+ source->cur_blocks, source->max_blocks,
+ source->cur_size, source->max_size, source->cur_max,
+ FT_FILENAME( source->file_name ),
+ source->line_no );
+ }
+ printf( "------------------------------------------------\n" );
+
+ ft_mem_table_free( table, sources );
+ }
+ }
+
+#else /* !FT_DEBUG_MEMORY */
+
+ /* ANSI C doesn't like empty source files */
+ static const FT_Byte _debug_mem_dummy = 0;
+
+#endif /* !FT_DEBUG_MEMORY */
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/base/ftdebug.c b/src/3rdparty/freetype/src/base/ftdebug.c
new file mode 100644
index 0000000000..2adbeabeb2
--- /dev/null
+++ b/src/3rdparty/freetype/src/base/ftdebug.c
@@ -0,0 +1,246 @@
+/***************************************************************************/
+/* */
+/* ftdebug.c */
+/* */
+/* Debugging and logging component (body). */
+/* */
+/* Copyright 1996-2001, 2002, 2004, 2008 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+ /*************************************************************************/
+ /* */
+ /* This component contains various macros and functions used to ease the */
+ /* debugging of the FreeType engine. Its main purpose is in assertion */
+ /* checking, tracing, and error detection. */
+ /* */
+ /* There are now three debugging modes: */
+ /* */
+ /* - trace mode */
+ /* */
+ /* Error and trace messages are sent to the log file (which can be the */
+ /* standard error output). */
+ /* */
+ /* - error mode */
+ /* */
+ /* Only error messages are generated. */
+ /* */
+ /* - release mode: */
+ /* */
+ /* No error message is sent or generated. The code is free from any */
+ /* debugging parts. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_INTERNAL_DEBUG_H
+
+
+#ifdef FT_DEBUG_LEVEL_ERROR
+
+ /* documentation is in ftdebug.h */
+
+ FT_BASE_DEF( void )
+ FT_Message( const char* fmt, ... )
+ {
+ va_list ap;
+
+
+ va_start( ap, fmt );
+ vfprintf( stderr, fmt, ap );
+ va_end( ap );
+ }
+
+
+ /* documentation is in ftdebug.h */
+
+ FT_BASE_DEF( void )
+ FT_Panic( const char* fmt, ... )
+ {
+ va_list ap;
+
+
+ va_start( ap, fmt );
+ vfprintf( stderr, fmt, ap );
+ va_end( ap );
+
+ exit( EXIT_FAILURE );
+ }
+
+#endif /* FT_DEBUG_LEVEL_ERROR */
+
+
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+
+ /* array of trace levels, initialized to 0 */
+ int ft_trace_levels[trace_count];
+
+
+ /* define array of trace toggle names */
+#define FT_TRACE_DEF( x ) #x ,
+
+ static const char* ft_trace_toggles[trace_count + 1] =
+ {
+#include FT_INTERNAL_TRACE_H
+ NULL
+ };
+
+#undef FT_TRACE_DEF
+
+
+ /* documentation is in ftdebug.h */
+
+ FT_BASE_DEF( FT_Int )
+ FT_Trace_Get_Count( void )
+ {
+ return trace_count;
+ }
+
+
+ /* documentation is in ftdebug.h */
+
+ FT_BASE_DEF( const char * )
+ FT_Trace_Get_Name( FT_Int idx )
+ {
+ int max = FT_Trace_Get_Count();
+
+
+ if ( idx < max )
+ return ft_trace_toggles[idx];
+ else
+ return NULL;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* Initialize the tracing sub-system. This is done by retrieving the */
+ /* value of the `FT2_DEBUG' environment variable. It must be a list of */
+ /* toggles, separated by spaces, `;', or `,'. Example: */
+ /* */
+ /* export FT2_DEBUG="any:3 memory:7 stream:5" */
+ /* */
+ /* This requests that all levels be set to 3, except the trace level for */
+ /* the memory and stream components which are set to 7 and 5, */
+ /* respectively. */
+ /* */
+ /* See the file <include/freetype/internal/fttrace.h> for details of the */
+ /* available toggle names. */
+ /* */
+ /* The level must be between 0 and 7; 0 means quiet (except for serious */
+ /* runtime errors), and 7 means _very_ verbose. */
+ /* */
+ FT_BASE_DEF( void )
+ ft_debug_init( void )
+ {
+ const char* ft2_debug = getenv( "FT2_DEBUG" );
+
+
+ if ( ft2_debug )
+ {
+ const char* p = ft2_debug;
+ const char* q;
+
+
+ for ( ; *p; p++ )
+ {
+ /* skip leading whitespace and separators */
+ if ( *p == ' ' || *p == '\t' || *p == ',' || *p == ';' || *p == '=' )
+ continue;
+
+ /* read toggle name, followed by ':' */
+ q = p;
+ while ( *p && *p != ':' )
+ p++;
+
+ if ( *p == ':' && p > q )
+ {
+ FT_Int n, i, len = (FT_Int)( p - q );
+ FT_Int level = -1, found = -1;
+
+
+ for ( n = 0; n < trace_count; n++ )
+ {
+ const char* toggle = ft_trace_toggles[n];
+
+
+ for ( i = 0; i < len; i++ )
+ {
+ if ( toggle[i] != q[i] )
+ break;
+ }
+
+ if ( i == len && toggle[i] == 0 )
+ {
+ found = n;
+ break;
+ }
+ }
+
+ /* read level */
+ p++;
+ if ( *p )
+ {
+ level = *p++ - '0';
+ if ( level < 0 || level > 7 )
+ level = -1;
+ }
+
+ if ( found >= 0 && level >= 0 )
+ {
+ if ( found == trace_any )
+ {
+ /* special case for `any' */
+ for ( n = 0; n < trace_count; n++ )
+ ft_trace_levels[n] = level;
+ }
+ else
+ ft_trace_levels[found] = level;
+ }
+ }
+ }
+ }
+ }
+
+
+#else /* !FT_DEBUG_LEVEL_TRACE */
+
+
+ FT_BASE_DEF( void )
+ ft_debug_init( void )
+ {
+ /* nothing */
+ }
+
+
+ FT_BASE_DEF( FT_Int )
+ FT_Trace_Get_Count( void )
+ {
+ return 0;
+ }
+
+
+ FT_BASE_DEF( const char * )
+ FT_Trace_Get_Name( FT_Int idx )
+ {
+ FT_UNUSED( idx );
+
+ return NULL;
+ }
+
+
+#endif /* !FT_DEBUG_LEVEL_TRACE */
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/base/ftfstype.c b/src/3rdparty/freetype/src/base/ftfstype.c
new file mode 100644
index 0000000000..d0ef7b7c1b
--- /dev/null
+++ b/src/3rdparty/freetype/src/base/ftfstype.c
@@ -0,0 +1,62 @@
+/***************************************************************************/
+/* */
+/* ftfstype.c */
+/* */
+/* FreeType utility file to access FSType data (body). */
+/* */
+/* Copyright 2008, 2009 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+#include <ft2build.h>
+#include FT_TYPE1_TABLES_H
+#include FT_TRUETYPE_TABLES_H
+#include FT_INTERNAL_SERVICE_H
+#include FT_SERVICE_POSTSCRIPT_INFO_H
+
+
+ /* documentation is in freetype.h */
+
+ FT_EXPORT_DEF( FT_UShort )
+ FT_Get_FSType_Flags( FT_Face face )
+ {
+ TT_OS2* os2;
+
+
+ /* first, try to get the fs_type directly from the font */
+ if ( face )
+ {
+ FT_Service_PsInfo service = NULL;
+
+
+ FT_FACE_FIND_SERVICE( face, service, POSTSCRIPT_INFO );
+
+ if ( service && service->ps_get_font_extra )
+ {
+ PS_FontExtraRec extra;
+
+
+ if ( !service->ps_get_font_extra( face, &extra ) &&
+ extra.fs_type != 0 )
+ return extra.fs_type;
+ }
+ }
+
+ /* look at FSType before fsType for Type42 */
+
+ if ( ( os2 = (TT_OS2*)FT_Get_Sfnt_Table( face, ft_sfnt_os2 ) ) != NULL &&
+ os2->version != 0xFFFFU )
+ return os2->fsType;
+
+ return 0;
+ }
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/base/ftgasp.c b/src/3rdparty/freetype/src/base/ftgasp.c
new file mode 100644
index 0000000000..8485d29259
--- /dev/null
+++ b/src/3rdparty/freetype/src/base/ftgasp.c
@@ -0,0 +1,61 @@
+/***************************************************************************/
+/* */
+/* ftgasp.c */
+/* */
+/* Access of TrueType's `gasp' table (body). */
+/* */
+/* Copyright 2007 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_GASP_H
+#include FT_INTERNAL_TRUETYPE_TYPES_H
+
+
+ FT_EXPORT_DEF( FT_Int )
+ FT_Get_Gasp( FT_Face face,
+ FT_UInt ppem )
+ {
+ FT_Int result = FT_GASP_NO_TABLE;
+
+
+ if ( face && FT_IS_SFNT( face ) )
+ {
+ TT_Face ttface = (TT_Face)face;
+
+
+ if ( ttface->gasp.numRanges > 0 )
+ {
+ TT_GaspRange range = ttface->gasp.gaspRanges;
+ TT_GaspRange range_end = range + ttface->gasp.numRanges;
+
+
+ while ( ppem > range->maxPPEM )
+ {
+ range++;
+ if ( range >= range_end )
+ goto Exit;
+ }
+
+ result = range->gaspFlag;
+
+ /* ensure that we don't have spurious bits */
+ if ( ttface->gasp.version == 0 )
+ result &= 3;
+ }
+ }
+ Exit:
+ return result;
+ }
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/base/ftgloadr.c b/src/3rdparty/freetype/src/base/ftgloadr.c
new file mode 100644
index 0000000000..ab52621ea6
--- /dev/null
+++ b/src/3rdparty/freetype/src/base/ftgloadr.c
@@ -0,0 +1,394 @@
+/***************************************************************************/
+/* */
+/* ftgloadr.c */
+/* */
+/* The FreeType glyph loader (body). */
+/* */
+/* Copyright 2002, 2003, 2004, 2005, 2006 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_GLYPH_LOADER_H
+#include FT_INTERNAL_MEMORY_H
+#include FT_INTERNAL_OBJECTS_H
+
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_gloader
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+ /***** *****/
+ /***** *****/
+ /***** G L Y P H L O A D E R *****/
+ /***** *****/
+ /***** *****/
+ /*************************************************************************/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* The glyph loader is a simple object which is used to load a set of */
+ /* glyphs easily. It is critical for the correct loading of composites. */
+ /* */
+ /* Ideally, one can see it as a stack of abstract `glyph' objects. */
+ /* */
+ /* loader.base Is really the bottom of the stack. It describes a */
+ /* single glyph image made of the juxtaposition of */
+ /* several glyphs (those `in the stack'). */
+ /* */
+ /* loader.current Describes the top of the stack, on which a new */
+ /* glyph can be loaded. */
+ /* */
+ /* Rewind Clears the stack. */
+ /* Prepare Set up `loader.current' for addition of a new glyph */
+ /* image. */
+ /* Add Add the `current' glyph image to the `base' one, */
+ /* and prepare for another one. */
+ /* */
+ /* The glyph loader is now a base object. Each driver used to */
+ /* re-implement it in one way or the other, which wasted code and */
+ /* energy. */
+ /* */
+ /*************************************************************************/
+
+
+ /* create a new glyph loader */
+ FT_BASE_DEF( FT_Error )
+ FT_GlyphLoader_New( FT_Memory memory,
+ FT_GlyphLoader *aloader )
+ {
+ FT_GlyphLoader loader;
+ FT_Error error;
+
+
+ if ( !FT_NEW( loader ) )
+ {
+ loader->memory = memory;
+ *aloader = loader;
+ }
+ return error;
+ }
+
+
+ /* rewind the glyph loader - reset counters to 0 */
+ FT_BASE_DEF( void )
+ FT_GlyphLoader_Rewind( FT_GlyphLoader loader )
+ {
+ FT_GlyphLoad base = &loader->base;
+ FT_GlyphLoad current = &loader->current;
+
+
+ base->outline.n_points = 0;
+ base->outline.n_contours = 0;
+ base->num_subglyphs = 0;
+
+ *current = *base;
+ }
+
+
+ /* reset the glyph loader, frees all allocated tables */
+ /* and starts from zero */
+ FT_BASE_DEF( void )
+ FT_GlyphLoader_Reset( FT_GlyphLoader loader )
+ {
+ FT_Memory memory = loader->memory;
+
+
+ FT_FREE( loader->base.outline.points );
+ FT_FREE( loader->base.outline.tags );
+ FT_FREE( loader->base.outline.contours );
+ FT_FREE( loader->base.extra_points );
+ FT_FREE( loader->base.subglyphs );
+
+ loader->base.extra_points2 = NULL;
+
+ loader->max_points = 0;
+ loader->max_contours = 0;
+ loader->max_subglyphs = 0;
+
+ FT_GlyphLoader_Rewind( loader );
+ }
+
+
+ /* delete a glyph loader */
+ FT_BASE_DEF( void )
+ FT_GlyphLoader_Done( FT_GlyphLoader loader )
+ {
+ if ( loader )
+ {
+ FT_Memory memory = loader->memory;
+
+
+ FT_GlyphLoader_Reset( loader );
+ FT_FREE( loader );
+ }
+ }
+
+
+ /* re-adjust the `current' outline fields */
+ static void
+ FT_GlyphLoader_Adjust_Points( FT_GlyphLoader loader )
+ {
+ FT_Outline* base = &loader->base.outline;
+ FT_Outline* current = &loader->current.outline;
+
+
+ current->points = base->points + base->n_points;
+ current->tags = base->tags + base->n_points;
+ current->contours = base->contours + base->n_contours;
+
+ /* handle extra points table - if any */
+ if ( loader->use_extra )
+ {
+ loader->current.extra_points = loader->base.extra_points +
+ base->n_points;
+
+ loader->current.extra_points2 = loader->base.extra_points2 +
+ base->n_points;
+ }
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_GlyphLoader_CreateExtra( FT_GlyphLoader loader )
+ {
+ FT_Error error;
+ FT_Memory memory = loader->memory;
+
+
+ if ( !FT_NEW_ARRAY( loader->base.extra_points, 2 * loader->max_points ) )
+ {
+ loader->use_extra = 1;
+ loader->base.extra_points2 = loader->base.extra_points +
+ loader->max_points;
+
+ FT_GlyphLoader_Adjust_Points( loader );
+ }
+ return error;
+ }
+
+
+ /* re-adjust the `current' subglyphs field */
+ static void
+ FT_GlyphLoader_Adjust_Subglyphs( FT_GlyphLoader loader )
+ {
+ FT_GlyphLoad base = &loader->base;
+ FT_GlyphLoad current = &loader->current;
+
+
+ current->subglyphs = base->subglyphs + base->num_subglyphs;
+ }
+
+
+ /* Ensure that we can add `n_points' and `n_contours' to our glyph. */
+ /* This function reallocates its outline tables if necessary. Note that */
+ /* it DOESN'T change the number of points within the loader! */
+ /* */
+ FT_BASE_DEF( FT_Error )
+ FT_GlyphLoader_CheckPoints( FT_GlyphLoader loader,
+ FT_UInt n_points,
+ FT_UInt n_contours )
+ {
+ FT_Memory memory = loader->memory;
+ FT_Error error = FT_Err_Ok;
+ FT_Outline* base = &loader->base.outline;
+ FT_Outline* current = &loader->current.outline;
+ FT_Bool adjust = 0;
+
+ FT_UInt new_max, old_max;
+
+
+ /* check points & tags */
+ new_max = base->n_points + current->n_points + n_points;
+ old_max = loader->max_points;
+
+ if ( new_max > old_max )
+ {
+ new_max = FT_PAD_CEIL( new_max, 8 );
+
+ if ( FT_RENEW_ARRAY( base->points, old_max, new_max ) ||
+ FT_RENEW_ARRAY( base->tags, old_max, new_max ) )
+ goto Exit;
+
+ if ( loader->use_extra )
+ {
+ if ( FT_RENEW_ARRAY( loader->base.extra_points,
+ old_max * 2, new_max * 2 ) )
+ goto Exit;
+
+ FT_ARRAY_MOVE( loader->base.extra_points + new_max,
+ loader->base.extra_points + old_max,
+ old_max );
+
+ loader->base.extra_points2 = loader->base.extra_points + new_max;
+ }
+
+ adjust = 1;
+ loader->max_points = new_max;
+ }
+
+ /* check contours */
+ old_max = loader->max_contours;
+ new_max = base->n_contours + current->n_contours +
+ n_contours;
+ if ( new_max > old_max )
+ {
+ new_max = FT_PAD_CEIL( new_max, 4 );
+ if ( FT_RENEW_ARRAY( base->contours, old_max, new_max ) )
+ goto Exit;
+
+ adjust = 1;
+ loader->max_contours = new_max;
+ }
+
+ if ( adjust )
+ FT_GlyphLoader_Adjust_Points( loader );
+
+ Exit:
+ return error;
+ }
+
+
+ /* Ensure that we can add `n_subglyphs' to our glyph. this function */
+ /* reallocates its subglyphs table if necessary. Note that it DOES */
+ /* NOT change the number of subglyphs within the loader! */
+ /* */
+ FT_BASE_DEF( FT_Error )
+ FT_GlyphLoader_CheckSubGlyphs( FT_GlyphLoader loader,
+ FT_UInt n_subs )
+ {
+ FT_Memory memory = loader->memory;
+ FT_Error error = FT_Err_Ok;
+ FT_UInt new_max, old_max;
+
+ FT_GlyphLoad base = &loader->base;
+ FT_GlyphLoad current = &loader->current;
+
+
+ new_max = base->num_subglyphs + current->num_subglyphs + n_subs;
+ old_max = loader->max_subglyphs;
+ if ( new_max > old_max )
+ {
+ new_max = FT_PAD_CEIL( new_max, 2 );
+ if ( FT_RENEW_ARRAY( base->subglyphs, old_max, new_max ) )
+ goto Exit;
+
+ loader->max_subglyphs = new_max;
+
+ FT_GlyphLoader_Adjust_Subglyphs( loader );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ /* prepare loader for the addition of a new glyph on top of the base one */
+ FT_BASE_DEF( void )
+ FT_GlyphLoader_Prepare( FT_GlyphLoader loader )
+ {
+ FT_GlyphLoad current = &loader->current;
+
+
+ current->outline.n_points = 0;
+ current->outline.n_contours = 0;
+ current->num_subglyphs = 0;
+
+ FT_GlyphLoader_Adjust_Points ( loader );
+ FT_GlyphLoader_Adjust_Subglyphs( loader );
+ }
+
+
+ /* add current glyph to the base image - and prepare for another */
+ FT_BASE_DEF( void )
+ FT_GlyphLoader_Add( FT_GlyphLoader loader )
+ {
+ FT_GlyphLoad base;
+ FT_GlyphLoad current;
+
+ FT_UInt n_curr_contours;
+ FT_UInt n_base_points;
+ FT_UInt n;
+
+
+ if ( !loader )
+ return;
+
+ base = &loader->base;
+ current = &loader->current;
+
+ n_curr_contours = current->outline.n_contours;
+ n_base_points = base->outline.n_points;
+
+ base->outline.n_points =
+ (short)( base->outline.n_points + current->outline.n_points );
+ base->outline.n_contours =
+ (short)( base->outline.n_contours + current->outline.n_contours );
+
+ base->num_subglyphs += current->num_subglyphs;
+
+ /* adjust contours count in newest outline */
+ for ( n = 0; n < n_curr_contours; n++ )
+ current->outline.contours[n] =
+ (short)( current->outline.contours[n] + n_base_points );
+
+ /* prepare for another new glyph image */
+ FT_GlyphLoader_Prepare( loader );
+ }
+
+
+ FT_BASE_DEF( FT_Error )
+ FT_GlyphLoader_CopyPoints( FT_GlyphLoader target,
+ FT_GlyphLoader source )
+ {
+ FT_Error error;
+ FT_UInt num_points = source->base.outline.n_points;
+ FT_UInt num_contours = source->base.outline.n_contours;
+
+
+ error = FT_GlyphLoader_CheckPoints( target, num_points, num_contours );
+ if ( !error )
+ {
+ FT_Outline* out = &target->base.outline;
+ FT_Outline* in = &source->base.outline;
+
+
+ FT_ARRAY_COPY( out->points, in->points,
+ num_points );
+ FT_ARRAY_COPY( out->tags, in->tags,
+ num_points );
+ FT_ARRAY_COPY( out->contours, in->contours,
+ num_contours );
+
+ /* do we need to copy the extra points? */
+ if ( target->use_extra && source->use_extra )
+ {
+ FT_ARRAY_COPY( target->base.extra_points, source->base.extra_points,
+ num_points );
+ FT_ARRAY_COPY( target->base.extra_points2, source->base.extra_points2,
+ num_points );
+ }
+
+ out->n_points = (short)num_points;
+ out->n_contours = (short)num_contours;
+
+ FT_GlyphLoader_Adjust_Points( target );
+ }
+
+ return error;
+ }
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/base/ftglyph.c b/src/3rdparty/freetype/src/base/ftglyph.c
new file mode 100644
index 0000000000..4130cb1102
--- /dev/null
+++ b/src/3rdparty/freetype/src/base/ftglyph.c
@@ -0,0 +1,626 @@
+/***************************************************************************/
+/* */
+/* ftglyph.c */
+/* */
+/* FreeType convenience functions to handle glyphs (body). */
+/* */
+/* Copyright 1996-2001, 2002, 2003, 2004, 2005, 2007, 2008 by */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+ /*************************************************************************/
+ /* */
+ /* This file contains the definition of several convenience functions */
+ /* that can be used by client applications to easily retrieve glyph */
+ /* bitmaps and outlines from a given face. */
+ /* */
+ /* These functions should be optional if you are writing a font server */
+ /* or text layout engine on top of FreeType. However, they are pretty */
+ /* handy for many other simple uses of the library. */
+ /* */
+ /*************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_GLYPH_H
+#include FT_OUTLINE_H
+#include FT_BITMAP_H
+#include FT_INTERNAL_OBJECTS_H
+
+
+ /*************************************************************************/
+ /* */
+ /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
+ /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
+ /* messages during execution. */
+ /* */
+#undef FT_COMPONENT
+#define FT_COMPONENT trace_glyph
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** FT_BitmapGlyph support ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ FT_CALLBACK_DEF( FT_Error )
+ ft_bitmap_glyph_init( FT_Glyph bitmap_glyph,
+ FT_GlyphSlot slot )
+ {
+ FT_BitmapGlyph glyph = (FT_BitmapGlyph)bitmap_glyph;
+ FT_Error error = FT_Err_Ok;
+ FT_Library library = FT_GLYPH( glyph )->library;
+
+
+ if ( slot->format != FT_GLYPH_FORMAT_BITMAP )
+ {
+ error = FT_Err_Invalid_Glyph_Format;
+ goto Exit;
+ }
+
+ glyph->left = slot->bitmap_left;
+ glyph->top = slot->bitmap_top;
+
+ /* do lazy copying whenever possible */
+ if ( slot->internal->flags & FT_GLYPH_OWN_BITMAP )
+ {
+ glyph->bitmap = slot->bitmap;
+ slot->internal->flags &= ~FT_GLYPH_OWN_BITMAP;
+ }
+ else
+ {
+ FT_Bitmap_New( &glyph->bitmap );
+ error = FT_Bitmap_Copy( library, &slot->bitmap, &glyph->bitmap );
+ }
+
+ Exit:
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ft_bitmap_glyph_copy( FT_Glyph bitmap_source,
+ FT_Glyph bitmap_target )
+ {
+ FT_Library library = bitmap_source->library;
+ FT_BitmapGlyph source = (FT_BitmapGlyph)bitmap_source;
+ FT_BitmapGlyph target = (FT_BitmapGlyph)bitmap_target;
+
+
+ target->left = source->left;
+ target->top = source->top;
+
+ return FT_Bitmap_Copy( library, &source->bitmap, &target->bitmap );
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ft_bitmap_glyph_done( FT_Glyph bitmap_glyph )
+ {
+ FT_BitmapGlyph glyph = (FT_BitmapGlyph)bitmap_glyph;
+ FT_Library library = FT_GLYPH( glyph )->library;
+
+
+ FT_Bitmap_Done( library, &glyph->bitmap );
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ft_bitmap_glyph_bbox( FT_Glyph bitmap_glyph,
+ FT_BBox* cbox )
+ {
+ FT_BitmapGlyph glyph = (FT_BitmapGlyph)bitmap_glyph;
+
+
+ cbox->xMin = glyph->left << 6;
+ cbox->xMax = cbox->xMin + ( glyph->bitmap.width << 6 );
+ cbox->yMax = glyph->top << 6;
+ cbox->yMin = cbox->yMax - ( glyph->bitmap.rows << 6 );
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Glyph_Class ft_bitmap_glyph_class =
+ {
+ sizeof ( FT_BitmapGlyphRec ),
+ FT_GLYPH_FORMAT_BITMAP,
+
+ ft_bitmap_glyph_init,
+ ft_bitmap_glyph_done,
+ ft_bitmap_glyph_copy,
+ 0, /* FT_Glyph_TransformFunc */
+ ft_bitmap_glyph_bbox,
+ 0 /* FT_Glyph_PrepareFunc */
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** FT_OutlineGlyph support ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ft_outline_glyph_init( FT_Glyph outline_glyph,
+ FT_GlyphSlot slot )
+ {
+ FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph;
+ FT_Error error = FT_Err_Ok;
+ FT_Library library = FT_GLYPH( glyph )->library;
+ FT_Outline* source = &slot->outline;
+ FT_Outline* target = &glyph->outline;
+
+
+ /* check format in glyph slot */
+ if ( slot->format != FT_GLYPH_FORMAT_OUTLINE )
+ {
+ error = FT_Err_Invalid_Glyph_Format;
+ goto Exit;
+ }
+
+ /* allocate new outline */
+ error = FT_Outline_New( library, source->n_points, source->n_contours,
+ &glyph->outline );
+ if ( error )
+ goto Exit;
+
+ FT_Outline_Copy( source, target );
+
+ Exit:
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ft_outline_glyph_done( FT_Glyph outline_glyph )
+ {
+ FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph;
+
+
+ FT_Outline_Done( FT_GLYPH( glyph )->library, &glyph->outline );
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ft_outline_glyph_copy( FT_Glyph outline_source,
+ FT_Glyph outline_target )
+ {
+ FT_OutlineGlyph source = (FT_OutlineGlyph)outline_source;
+ FT_OutlineGlyph target = (FT_OutlineGlyph)outline_target;
+ FT_Error error;
+ FT_Library library = FT_GLYPH( source )->library;
+
+
+ error = FT_Outline_New( library, source->outline.n_points,
+ source->outline.n_contours, &target->outline );
+ if ( !error )
+ FT_Outline_Copy( &source->outline, &target->outline );
+
+ return error;
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ft_outline_glyph_transform( FT_Glyph outline_glyph,
+ const FT_Matrix* matrix,
+ const FT_Vector* delta )
+ {
+ FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph;
+
+
+ if ( matrix )
+ FT_Outline_Transform( &glyph->outline, matrix );
+
+ if ( delta )
+ FT_Outline_Translate( &glyph->outline, delta->x, delta->y );
+ }
+
+
+ FT_CALLBACK_DEF( void )
+ ft_outline_glyph_bbox( FT_Glyph outline_glyph,
+ FT_BBox* bbox )
+ {
+ FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph;
+
+
+ FT_Outline_Get_CBox( &glyph->outline, bbox );
+ }
+
+
+ FT_CALLBACK_DEF( FT_Error )
+ ft_outline_glyph_prepare( FT_Glyph outline_glyph,
+ FT_GlyphSlot slot )
+ {
+ FT_OutlineGlyph glyph = (FT_OutlineGlyph)outline_glyph;
+
+
+ slot->format = FT_GLYPH_FORMAT_OUTLINE;
+ slot->outline = glyph->outline;
+ slot->outline.flags &= ~FT_OUTLINE_OWNER;
+
+ return FT_Err_Ok;
+ }
+
+
+ FT_CALLBACK_TABLE_DEF
+ const FT_Glyph_Class ft_outline_glyph_class =
+ {
+ sizeof ( FT_OutlineGlyphRec ),
+ FT_GLYPH_FORMAT_OUTLINE,
+
+ ft_outline_glyph_init,
+ ft_outline_glyph_done,
+ ft_outline_glyph_copy,
+ ft_outline_glyph_transform,
+ ft_outline_glyph_bbox,
+ ft_outline_glyph_prepare
+ };
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /**** ****/
+ /**** FT_Glyph class and API ****/
+ /**** ****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ static FT_Error
+ ft_new_glyph( FT_Library library,
+ const FT_Glyph_Class* clazz,
+ FT_Glyph* aglyph )
+ {
+ FT_Memory memory = library->memory;
+ FT_Error error;
+ FT_Glyph glyph;
+
+
+ *aglyph = 0;
+
+ if ( !FT_ALLOC( glyph, clazz->glyph_size ) )
+ {
+ glyph->library = library;
+ glyph->clazz = clazz;
+ glyph->format = clazz->glyph_format;
+
+ *aglyph = glyph;
+ }
+
+ return error;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Glyph_Copy( FT_Glyph source,
+ FT_Glyph *target )
+ {
+ FT_Glyph copy;
+ FT_Error error;
+ const FT_Glyph_Class* clazz;
+
+
+ /* check arguments */
+ if ( !target )
+ {
+ error = FT_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ *target = 0;
+
+ if ( !source || !source->clazz )
+ {
+ error = FT_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ clazz = source->clazz;
+ error = ft_new_glyph( source->library, clazz, &copy );
+ if ( error )
+ goto Exit;
+
+ copy->advance = source->advance;
+ copy->format = source->format;
+
+ if ( clazz->glyph_copy )
+ error = clazz->glyph_copy( source, copy );
+
+ if ( error )
+ FT_Done_Glyph( copy );
+ else
+ *target = copy;
+
+ Exit:
+ return error;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Get_Glyph( FT_GlyphSlot slot,
+ FT_Glyph *aglyph )
+ {
+ FT_Library library;
+ FT_Error error;
+ FT_Glyph glyph;
+
+ const FT_Glyph_Class* clazz = 0;
+
+
+ if ( !slot )
+ return FT_Err_Invalid_Slot_Handle;
+
+ library = slot->library;
+
+ if ( !aglyph )
+ return FT_Err_Invalid_Argument;
+
+ /* if it is a bitmap, that's easy :-) */
+ if ( slot->format == FT_GLYPH_FORMAT_BITMAP )
+ clazz = &ft_bitmap_glyph_class;
+
+ /* it it is an outline too */
+ else if ( slot->format == FT_GLYPH_FORMAT_OUTLINE )
+ clazz = &ft_outline_glyph_class;
+
+ else
+ {
+ /* try to find a renderer that supports the glyph image format */
+ FT_Renderer render = FT_Lookup_Renderer( library, slot->format, 0 );
+
+
+ if ( render )
+ clazz = &render->glyph_class;
+ }
+
+ if ( !clazz )
+ {
+ error = FT_Err_Invalid_Glyph_Format;
+ goto Exit;
+ }
+
+ /* create FT_Glyph object */
+ error = ft_new_glyph( library, clazz, &glyph );
+ if ( error )
+ goto Exit;
+
+ /* copy advance while converting it to 16.16 format */
+ glyph->advance.x = slot->advance.x << 10;
+ glyph->advance.y = slot->advance.y << 10;
+
+ /* now import the image from the glyph slot */
+ error = clazz->glyph_init( glyph, slot );
+
+ /* if an error occurred, destroy the glyph */
+ if ( error )
+ FT_Done_Glyph( glyph );
+ else
+ *aglyph = glyph;
+
+ Exit:
+ return error;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Glyph_Transform( FT_Glyph glyph,
+ FT_Matrix* matrix,
+ FT_Vector* delta )
+ {
+ const FT_Glyph_Class* clazz;
+ FT_Error error = FT_Err_Ok;
+
+
+ if ( !glyph || !glyph->clazz )
+ error = FT_Err_Invalid_Argument;
+ else
+ {
+ clazz = glyph->clazz;
+ if ( clazz->glyph_transform )
+ {
+ /* transform glyph image */
+ clazz->glyph_transform( glyph, matrix, delta );
+
+ /* transform advance vector */
+ if ( matrix )
+ FT_Vector_Transform( &glyph->advance, matrix );
+ }
+ else
+ error = FT_Err_Invalid_Glyph_Format;
+ }
+ return error;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Glyph_Get_CBox( FT_Glyph glyph,
+ FT_UInt bbox_mode,
+ FT_BBox *acbox )
+ {
+ const FT_Glyph_Class* clazz;
+
+
+ if ( !acbox )
+ return;
+
+ acbox->xMin = acbox->yMin = acbox->xMax = acbox->yMax = 0;
+
+ if ( !glyph || !glyph->clazz )
+ return;
+ else
+ {
+ clazz = glyph->clazz;
+ if ( !clazz->glyph_bbox )
+ return;
+ else
+ {
+ /* retrieve bbox in 26.6 coordinates */
+ clazz->glyph_bbox( glyph, acbox );
+
+ /* perform grid fitting if needed */
+ if ( bbox_mode == FT_GLYPH_BBOX_GRIDFIT ||
+ bbox_mode == FT_GLYPH_BBOX_PIXELS )
+ {
+ acbox->xMin = FT_PIX_FLOOR( acbox->xMin );
+ acbox->yMin = FT_PIX_FLOOR( acbox->yMin );
+ acbox->xMax = FT_PIX_CEIL( acbox->xMax );
+ acbox->yMax = FT_PIX_CEIL( acbox->yMax );
+ }
+
+ /* convert to integer pixels if needed */
+ if ( bbox_mode == FT_GLYPH_BBOX_TRUNCATE ||
+ bbox_mode == FT_GLYPH_BBOX_PIXELS )
+ {
+ acbox->xMin >>= 6;
+ acbox->yMin >>= 6;
+ acbox->xMax >>= 6;
+ acbox->yMax >>= 6;
+ }
+ }
+ }
+ return;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_Glyph_To_Bitmap( FT_Glyph* the_glyph,
+ FT_Render_Mode render_mode,
+ FT_Vector* origin,
+ FT_Bool destroy )
+ {
+ FT_GlyphSlotRec dummy;
+ FT_GlyphSlot_InternalRec dummy_internal;
+ FT_Error error = FT_Err_Ok;
+ FT_Glyph glyph;
+ FT_BitmapGlyph bitmap = NULL;
+
+ const FT_Glyph_Class* clazz;
+
+
+ /* check argument */
+ if ( !the_glyph )
+ goto Bad;
+
+ /* we render the glyph into a glyph bitmap using a `dummy' glyph slot */
+ /* then calling FT_Render_Glyph_Internal() */
+
+ glyph = *the_glyph;
+ if ( !glyph )
+ goto Bad;
+
+ clazz = glyph->clazz;
+
+ /* when called with a bitmap glyph, do nothing and return successfully */
+ if ( clazz == &ft_bitmap_glyph_class )
+ goto Exit;
+
+ if ( !clazz || !clazz->glyph_prepare )
+ goto Bad;
+
+ FT_MEM_ZERO( &dummy, sizeof ( dummy ) );
+ FT_MEM_ZERO( &dummy_internal, sizeof ( dummy_internal ) );
+ dummy.internal = &dummy_internal;
+ dummy.library = glyph->library;
+ dummy.format = clazz->glyph_format;
+
+ /* create result bitmap glyph */
+ error = ft_new_glyph( glyph->library, &ft_bitmap_glyph_class,
+ (FT_Glyph*)(void*)&bitmap );
+ if ( error )
+ goto Exit;
+
+#if 1
+ /* if `origin' is set, translate the glyph image */
+ if ( origin )
+ FT_Glyph_Transform( glyph, 0, origin );
+#else
+ FT_UNUSED( origin );
+#endif
+
+ /* prepare dummy slot for rendering */
+ error = clazz->glyph_prepare( glyph, &dummy );
+ if ( !error )
+ error = FT_Render_Glyph_Internal( glyph->library, &dummy, render_mode );
+
+#if 1
+ if ( !destroy && origin )
+ {
+ FT_Vector v;
+
+
+ v.x = -origin->x;
+ v.y = -origin->y;
+ FT_Glyph_Transform( glyph, 0, &v );
+ }
+#endif
+
+ if ( error )
+ goto Exit;
+
+ /* in case of success, copy the bitmap to the glyph bitmap */
+ error = ft_bitmap_glyph_init( (FT_Glyph)bitmap, &dummy );
+ if ( error )
+ goto Exit;
+
+ /* copy advance */
+ bitmap->root.advance = glyph->advance;
+
+ if ( destroy )
+ FT_Done_Glyph( glyph );
+
+ *the_glyph = FT_GLYPH( bitmap );
+
+ Exit:
+ if ( error && bitmap )
+ FT_Done_Glyph( FT_GLYPH( bitmap ) );
+
+ return error;
+
+ Bad:
+ error = FT_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+
+ /* documentation is in ftglyph.h */
+
+ FT_EXPORT_DEF( void )
+ FT_Done_Glyph( FT_Glyph glyph )
+ {
+ if ( glyph )
+ {
+ FT_Memory memory = glyph->library->memory;
+ const FT_Glyph_Class* clazz = glyph->clazz;
+
+
+ if ( clazz->glyph_done )
+ clazz->glyph_done( glyph );
+
+ FT_FREE( glyph );
+ }
+ }
+
+
+/* END */
diff --git a/src/3rdparty/freetype/src/base/ftgxval.c b/src/3rdparty/freetype/src/base/ftgxval.c
new file mode 100644
index 0000000000..32662bed87
--- /dev/null
+++ b/src/3rdparty/freetype/src/base/ftgxval.c
@@ -0,0 +1,129 @@
+/***************************************************************************/
+/* */
+/* ftgxval.c */
+/* */
+/* FreeType API for validating TrueTyepGX/AAT tables (body). */
+/* */
+/* Copyright 2004, 2005, 2006 by */
+/* Masatake YAMATO, Redhat K.K, */
+/* David Turner, Robert Wilhelm, and Werner Lemberg. */
+/* */
+/* This file is part of the FreeType project, and may only be used, */
+/* modified, and distributed under the terms of the FreeType project */
+/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
+/* this file you indicate that you have read the license and */
+/* understand and accept it fully. */
+/* */
+/***************************************************************************/
+
+/***************************************************************************/
+/* */
+/* gxvalid is derived from both gxlayout module and otvalid module. */
+/* Development of gxlayout is supported by the Information-technology */
+/* Promotion Agency(IPA), Japan. */
+/* */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_SERVICE_GX_VALIDATE_H
+
+
+ /* documentation is in ftgxval.h */
+
+ FT_EXPORT_DEF( FT_Error )
+ FT_TrueTypeGX_Validate( FT_Face face,
+ FT_UInt validation_flags,
+ FT_Bytes tables[FT_VALIDATE_GX_LENGTH],
+ FT_UInt table_length )
+ {
+ FT_Service_GXvalidate service;
+ FT_Error error;
+
+
+ if ( !face )
+ {
+ error = FT_Err_Invalid_Face_Handle;
+ goto Exit;
+ }
+
+ if ( tables == NULL )
+ {
+ error = FT_Err_Invalid_Argument;
+ goto Exit;
+ }
+
+ FT_FACE_FIND_GLOBAL_SERVICE( face, service, GX_VALIDATE );
+
+ if ( service )
+ error = service->validate( face,
+ validation_flags,
+ tables,
+ table_length );
+ else
+ error = FT_Err_Unimplemente